我理解BlockingQueue的理论和概念,但是当我查看implementation的LinkedBlockingQueue时。我不知道为什么我们使用while
循环继续尝试并在take()
方法的第8行中等待(put()
相同)。我认为if
检查就足够了,因为从signalNotEmpty()
调用的put()
只在第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();
}
答案 0 :(得分:2)
因为虚假唤醒。请阅读条件类的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.
答案 1 :(得分:1)
原因是&#34;虚假的唤醒&#34;。看到: http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#wait()
答案 2 :(得分:-1)
这是为了捕获竞争条件,如果多个线程正在等待并且它们都被唤醒,其他一些线程可能已经采用了信号量计数,因此每个线程需要再次检查。