在BlockingQueue中执行take()和put()

时间:2015-02-22 06:23:35

标签: java multithreading concurrency blockingqueue

我理解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();
}

3 个答案:

答案 0 :(得分:2)

因为虚假唤醒。请阅读条件类的javadoc 另见Do spurious wakeups actually happen?

* <h3>Implementation Considerations</h3>
 *
 * <p>When waiting upon a {@code Condition}, a &quot;<em>spurious
 * wakeup</em>&quot; 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)

这是为了捕获竞争条件,如果多个线程正在等待并且它们都被唤醒,其他一些线程可能已经采用了信号量计数,因此每个线程需要再次检查。