我了解BlockingQueue的理论和概念,但是当我查看implementation时对于 LinkedBlockingQueue。我不明白为什么我们使用 while
循环继续尝试并在 take()
方法的第 8 行等待(与 put()
相同>)。我认为 if
检查就足够了,因为从 put()
调用的 signalNotEmpty()
仅在第 27 行发出信号,但没有发出信号所有,所以只有一个等待线程会被唤醒,对吧?我想知道我错过了什么吗?有人可以解释一下为什么我们使用 while
而不是 if
这是代码片段
1 public E take() throws InterruptedException {
2 E x;
3 int c = -1;
4 final AtomicInteger count = this.count;
5 final ReentrantLock takeLock = this.takeLock;
6 takeLock.lockInterruptibly();
7 try {
8 while (count.get() == 0) {
9 notEmpty.await();
10 }
11 x = dequeue();
12 c = count.getAndDecrement();
13 if (c > 1)
14 notEmpty.signal();
15 } finally {
16 takeLock.unlock();
17 }
18 if (c == capacity)
19 signalNotFull();
20 return x;
21 }
22
23 private void signalNotEmpty() {
24 final ReentrantLock takeLock = this.takeLock;
25 takeLock.lock();
26 try {
27 notEmpty.signal();
28 } finally {
29 takeLock.unlock();
30 }
31 }
如果我们将第 8 行更改为
会发生什么if(count.get() == 0) {
notEmpty.await();
}
最佳答案
这是因为虚假唤醒。请阅读条件类的javadoc 另请参阅 Do spurious wakeups actually happen?
* <h3>Implementation Considerations</h3>
*
* <p>When waiting upon a {@code Condition}, a "<em>spurious
* wakeup</em>" is permitted to occur, in
* general, as a concession to the underlying platform semantics.
* This has little practical impact on most application programs as a
* {@code Condition} should always be waited upon in a loop, testing
* the state predicate that is being waited for. An implementation is
* free to remove the possibility of spurious wakeups but it is
* recommended that applications programmers always assume that they can
* occur and so always wait in a loop.
关于java - BlockingQueue 中的 take() 和 put() 实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28655173/