3 回答
TA贡献1860条经验 获得超9个赞
BlockingQueue 的javadoc(LinkedBlockingQueue的超类)声明:
BlockingQueue
实现是线程安全的。所有排队方法都使用内部锁或其他形式的并发控制以原子方式实现其效果。
“原子地”一词意味着如果两个操作(例如a put
和a take
)同时发生,那么实现将确保它们根据合同行为。效果会仿佛在put
之前发生get
,反之亦然。这也适用于边缘情况,例如具有一个元素的队列示例。
实际上,由于put
并且get
正在阻塞操作,因此两个操作的相对顺序无关紧要。与offer
/ poll
或add
/ remove
顺序做的事,但你无法控制它。
请注意,上述内容完全基于javadoc所说的内容。假设我已正确解释了javadoc,那么它适用于所有1个 BlockingQueue
实现,无论它们是使用一个还是两个锁......或者根本不使用。如果BlockingQueue
实现不像上面那样,那就是一个错误!
1 - 正确实现API的所有实现。这应该涵盖所有Java SE类。
TA贡献1859条经验 获得超6个赞
put
实施一个 LinkedBlockingQueue
public void put(E e) throws InterruptedException { // some lock and node code // the part that matters here try { while (count.get() == capacity) { notFull.await(); } // put the item in the queue. } finally { // not important here }}
基本上,在put
调用线程wait
中,容量小于最大持续时间。
即使将值放在队列上的线程抓取与take线程不同的锁,它也会等待将其添加到队列中,直到队列未满。
take
有一个类似的实现,notEmpty
而不是notFull
。
TA贡献1831条经验 获得超10个赞
经过2天的搜索,我终于明白了...当队列中只有一个项目时,根据LinkedBlocking Queue的设计,实际上有两个节点:虚拟头和真实项目(同时最后指向它)。确实,put thread和take thread都可以获得锁定,但是它们会修改队列的不同部分。
Put线程会调用
last = last.next = node; // last points to the only item in queue
拿线程会打电话
Node<E> h = head;
Node<E> first = h.next; // first also points to the only item in queue
h.next = h;
head = first;
E x = first.item;
first.item = null;
return x;
这两个线程的交集是最后指向put线程以及在线程中首先指向的线程。请注意,put thread仅修改last.item并且take thread仅修改first.next。虽然这两个线程修改了同一个对象实例,但它们会修改它的不同成员,并且不会导致任何线程冲突。
添加回答
举报