java - BlockingQueue 中的 take() 和 put() 实现

标签 java multithreading concurrency blockingqueue

我了解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 &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.

关于java - BlockingQueue 中的 take() 和 put() 实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28655173/

相关文章:

java - Mockito - 使用参数模拟方法

java - java jar文件输出上的php exec是空数组

c# - 从后台线程通知 UI 线程

python - PyCharm:如何在多线程代码中使用断点?

python - 与队列一起使用时 "threads"列表变量的用途是什么

android - Dalvik VM 和 Java 内存模型(Android 上的并发编程)

mongodb - 如何在考虑并发性的情况下更新多行?

java - 自动化 Spring Cloud 简介

rest - 事件溯源 - 如何处理竞争条件和 http 传递?

java - 使用正斜杠作为扫描仪分隔符