java - 当Java LinkedBlocking Queue只有一个元素时,如果同时放入和取出会发生什么?

标签 java multithreading queue

LinkedBlocking Queue 有两个锁,一个用于放入,一个用于取出。当队列的大小为1时,我认为两个线程可以同时锁定和操作队列,这将导致未定义的行为。我错了吗?

// method put:                             // method take:             
// put lock                                // take lock
 putLocK.lockInterruptibly();              takeLock.lockInterruptibly();                      
 ...                                       ...

 while(count.get() == capacity){           while(count.get() == 0){
   notFull.await();                          notEmpty.await();
 }                                         }
 enqueue(node);                            x = dequeue();

// method enqueue:                         // method dequeue:
  last = last.next = node;                 Node<E> h = head;    
 ...                                       Node<E> first = h.next;
                                           h.next = h;        
                                           head = first;     
                                           E x = first.item;     
                                           first.item = null;   
                                           return x;

显然,当队列中只有一项时,put 线程和 take 线程会锁定,因此它们将分别执行 enqueue 和 dequeue 方法中的代码。我的意思是,如果 take 线程进入方法出队,在所有指针修改之后,不会与入队中的代码发生冲突吗?

这里的链接说“然而,当队列为空时,争用就无法避免,因此需要额外的代码来处理这种常见的‘边缘’情况”

Is BlockingQueue completely thread safe in Java

最佳答案

javadoc对于 BlockingQueue(LinkedBlockingQueue 的父类(super class))来说:

BlockingQueue implementations are thread-safe. All queuing methods achieve their effects atomically using internal locks or other forms of concurrency control.

“原子”一词意味着如果两个操作(例如 puttake)同时发生,那么实现将确保它们的行为符合契约(Contract)。效果将如同put 发生在get 之前,反之亦然。这也适用于边缘情况,例如包含一个元素的队列示例。

事实上,由于 putget 是阻塞操作,因此这两个操作的相对顺序并不重要。使用 offer/polladd/remove 顺序确实很重要,但是你无法控制。


请注意,上述内容仅基于 javadoc 的内容。假设我正确解释了 javadoc,那么它适用于所有1 BlockingQueue 实现,无论它们是否使用一个或两个锁......或者根本不使用。如果 BlockingQueue 实现的行为与上述不同,那就是一个错误!

1 - 正确实现 API 的所有实现。这应该涵盖所有 Java SE 类。

关于java - 当Java LinkedBlocking Queue只有一个元素时,如果同时放入和取出会发生什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56114156/

相关文章:

java - Autowiring 构造函数时 Camel 没有路线

java - 无法在带有空格的批处理文件中启动命令

java - 需要敌人管理器在生成敌人之间等待

python - Deque 在 Python 中是如何工作的

c - 多级反馈队列初始化的结构

java - 防止值超出指定范围

java - CompletableFuture没有得到执行。如果我使用ExecutorService池,则其工作正常,但不使用默认的forkJoin公共(public)池

Swift OSX - 从另一个类或者线程更新 NSTextView

c++ - 在 allocate_stack (stack=<synthetic pointer>, pdp=<synthetic pointer>

android - Android 中的下载队列