如果在同步方法中调用 wait 方法,我的 java 单元测试失败

My java unit test failed if there is a call to wait method inside a synchronized method

最近在java学习多线程编程。而且我不明白为什么下面的测试用例会失败。任何解释将不胜感激。

这里是MyCounter.java.

public class MyCounter {
    private int count;

    public synchronized void incrementSynchronized() throws InterruptedException {
        int temp = count;
        wait(100);  // <-----
        count = temp + 1;
    }

    public int getCount() {
        return count;
    }
}

这是我的单元测试class。

public class MyCounterTest {
    @Test
    public void testSummationWithConcurrency() throws InterruptedException {
        int numberOfThreads = 100;
        ExecutorService service = Executors.newFixedThreadPool(10);
        CountDownLatch latch = new CountDownLatch(numberOfThreads);
        MyCounter counter = new MyCounter();
        for (int i = 0; i < numberOfThreads; i++) {
            service.submit(() -> {
                try {
                    counter.incrementSynchronized();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                latch.countDown();
            });
        }
        latch.await();
        assertEquals(numberOfThreads, counter.getCount());
    }
}

但是如果我从同步方法incrementSynchronized中删除wait(100),测试就会成功。不明白为什么wait(100)会影响结果

所罗门关于睡眠的建议很好。如果您使用睡眠而不是等待,您应该会看到测试通过。

使用 wait 会导致线程放弃锁,允许其他线程继续并覆盖计数中的值。当线程的等待超时时,它再次获取锁,然后写入一个值到现在可能已经过时的计数。

等待的典型用法是当您的线程在满足某些条件之前不能做任何有用的事情。其他某个线程最终满足该条件,并发送一条通知,通知该线程它可以恢复工作。与此同时,由于该线程无能为力,它释放了它持有的锁(因为其他线程需要锁才能使进程满足该线程正在等待的条件)并进入休眠状态。

休眠不释放锁,所以不会受到其他线程的干扰。对于休眠情况或删除等待调用的情况,锁在操作期间保持不变,没有其他任何东西可以更改计数,因此它是线程安全的。

请注意,在现实生活中,除了学习练习之外,抱着锁睡觉通常不是一个好主意。您希望最大限度地减少任务持有锁的时间,以便获得更高的吞吐量。相互拒绝使用锁的线程没有帮助。

还要注意 getCount 也需要同步,因为它正在读取另一个线程写入的值。