这是CountdownLatch的错误使用,初始计数= 1

时间:2013-12-27 07:59:23

标签: java multithreading

以下是Brain Goetz的书中“java concurrency in practice”中的代码片段5.11。

我觉得下面的代码令人困惑。似乎countdownlatch'startGate'有一个有缺陷的用法。 ('endGate'用法没问题)

public class TestHarness {
public long timeTasks(int nThreads, final Runnable task)
        throws InterruptedException {
    final CountDownLatch startGate = new CountDownLatch(1);
    final CountDownLatch endGate = new CountDownLatch(nThreads);
    for (int i = 0; i < nThreads; i++) {
        Thread t = new Thread() {
            public void run() {
                try {
                    startGate.await();
                    try {
                        task.run();
                    } finally {
                        endGate.countDown();
                    }
                } catch (InterruptedException ignored) {
                }
            }
        };
        t.start();
    }
    long start = System.nanoTime();
    startGate.countDown();
    endGate.await();
    long end = System.nanoTime();
    return end - start;
}

}

执行行startGate.countDown()将通知所有等待锁存器的工作线程。但这是否保证通知所有nThreads?
很可能只有少数线程,比如2个线程,nTheads执行run()方法的startGate.await()调用。
此时主线程执行startGate.countDown()。此调用将仅通知等待锁存器的2个线程(nThreads中)。

现在剩下的其他线程(nThread - 2)将在稍后调用startGate.await(),但由于主线程已经发出通知,因此工作线程(nThreads-2)现在将无限期地等待通知?

或者我错过了什么?

3 个答案:

答案 0 :(得分:3)

调用startGate.countDown();后,计数为零(因为它从1开始)。随后对startGate.await();的任何调用......都不要等待;它被归倒为零。

来自Javadocs for CountDownLatch.await()

  

如果当前计数为零,则此方法立即返回。

CountDownLatch仅用于阻止线程,直到完成另一个线程中的某些工作。完成该工作后,锁存器将计数到零,允许任何等待或将来的线程继续通过它。

答案 1 :(得分:1)

CountDownLatch countDown() 不像通知可以错过,但就像 Gate 。因此,一旦大门打开,它就会随时打开。因此,将直接允许调用await()的其他线程, 不阻止

答案 2 :(得分:0)

感谢@Brain和@Narendra的回答。刚刚浏览了CountDownLatch和AbstractQueuedSynchroniser类的源代码,我想补充一些细节。

它不是基于wait()notify()的系统,由于CountdownLatch.await()方法,我错误地假设了这个系统。

  • CountdownLatch.countDown():如果当前计数等于0,则它什么也不做,只是返回。否则,它首先将计数减少1,然后检查它是否为0.如果为0,则释放'共享'。

  • CountdownLatch.await():检查当前计数,如果它等于0(可能在两者之间中断),那么它什么也不做,只是返回。此方法仅在计数&gt;时获取'共享'。 0(或不中断)。

似乎latch = new CountDownLatch(0)这样的声明虽然无害,但却是一个毫无价值的声明,并且应该在构造函数代码中引发异常,就像它对count&lt; 0