下面是由Brain编写的“java并发实践”一书中的清单5.11。
我发现下面的代码令人费解。倒计时锁存的'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个线程)执行了run()方法的startGate.await()调用。
此时,主线程执行startGate.countDown()。此调用将只通知等待锁存的2个线程(退出nThreads )。
现在,其他线程( nThread - 2)稍后将调用startGate.await(),但由于主线程已经发出通知,所以工作线程(nThread-2)现在将无限期地等待通知?
还是我漏掉了什么?
发布于 2013-12-27 08:04:20
一旦startGate.countDown();被调用,计数是零(因为它从1开始)。后来打给startGate.await();的电话..。别等了,已经算成零了。
来自CountDownLatch.await()
如果当前计数为零,则此方法将立即返回。
CountDownLatch只用于阻塞线程,直到另一个线程中的某些工作完成为止。工作完成后,锁存器被计数为零,允许任何等待线程或未来线程继续通过它。
发布于 2013-12-27 08:13:00
CountDownLatch countDown()不是一个可以忽略的通知,而是一个Gate。因此,一旦大门打开,它在任何时候都是开放的。因此,调用await()的其他线程将直接被允许,而不阻塞。
发布于 2013-12-27 10:02:38
感谢“大脑”和“纳伦德拉”的回答。刚刚看过了CountDownLatch和AbstractQueuedSynchroniser类的源代码之后,我想添加一些更多的细节。
这不是一个基于wait()和notify()的系统,我错误地认为这是因为CountdownLatch.await()方法。
CountdownLatch.countDown():如果当前计数等于0,那么它什么也不做,只返回。否则,它首先将计数减少1,然后检查它是否为0。如果为0,则释放“共享”。CountdownLatch.await():检查当前计数,如果它等于0(可能在两者之间被中断),那么它什么也不做,只返回。只有在计数>0(或未被中断)时,此方法才能获得“共享”。看起来像latch = new CountDownLatch(0)这样的声明虽然无害,但却是一个毫无价值的声明,应该在构造函数代码中引发异常,就像它对count < 0所做的那样。
https://stackoverflow.com/questions/20797051
复制相似问题