我知道这个问题之前已经被问过并回答过很多次了,但我只是无法根据互联网上找到的示例找出窍门,例如this http://tutorials.jenkov.com/java-concurrency/blocking-queues.html or that https://codereview.stackexchange.com/questions/7002/java-blocking-queue one.
这两种解决方案都会检查阻塞队列的数组/队列/链表是否为空notifyAll
等待线程put()
方法,反之亦然get()
方法。 Acomment https://codereview.stackexchange.com/a/8334在第二个链接中强调了这种情况并提到这是没有必要的。
所以问题是;检查队列是否为空对我来说似乎也有点奇怪 | full 通知所有等待线程。有任何想法吗?
提前致谢。
我知道这是一个老问题了,但是在阅读了问题和答案之后我忍不住了,我希望你发现这很有用。
关于在通知其他等待线程之前检查队列实际上是满还是空,您错过了这两种方法put (T t)
and T get()
都是synchronized
方法,这意味着一次只有一个线程可以进入这些方法之一,但这并不会阻止它们一起工作,所以如果一个线程-a进入了put (T t)
方法另一个线程b仍然可以进入并开始执行中的指令T get()
线程a退出之前的方法put (T t)
,所以这个double-checking
这种设计会让开发人员感到更安全,因为你无法知道未来的 cpu 上下文切换是否会或何时会发生。
更好、更推荐的方法是使用Reentrant Locks
and Conditions
:
//我已经编辑了源代码link https://codereview.stackexchange.com/questions/7002/java-blocking-queue
Condition isFullCondition;
Condition isEmptyCondition;
Lock lock;
public BQueue() {
this(Integer.MAX_VALUE);
}
public BQueue(int limit) {
this.limit = limit;
lock = new ReentrantLock();
isFullCondition = lock.newCondition();
isEmptyCondition = lock.newCondition();
}
public void put (T t) {
lock.lock();
try {
while (isFull()) {
try {
isFullCondition.await();
} catch (InterruptedException ex) {}
}
q.add(t);
isEmptyCondition.signalAll();
} finally {
lock.unlock();
}
}
public T get() {
T t = null;
lock.lock();
try {
while (isEmpty()) {
try {
isEmptyCondition.await();
} catch (InterruptedException ex) {}
}
t = q.poll();
isFullCondition.signalAll();
} finally {
lock.unlock();
}
return t;
}
使用这种方法不需要double checking
,因为lock
对象在两个方法之间共享,这意味着一次只有一个线程 a 或 b 可以进入这些方法中的任何一个,这与创建不同监视器的同步方法不同,并且只有那些因为队列已满而等待的线程才会在有更多空间时收到通知,等待的线程也是如此,因为队列为空,这将导致更好的 CPU 利用率。
您可以通过源代码找到更详细的示例here http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/locks/Condition.html
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)