我知道这个问题之前已经被问过和回答过很多次了,但我就是想不出在互联网上找到的例子中的技巧,比如 this或 that一个。
这两种解决方案都在 put()
方法中检查阻塞队列的数组/队列/链表是否为 notifyAll
等待线程,反之亦然 get ()
方法。 comment在第二个链接中强调了这种情况并提到没有必要。
所以问题是;检查队列是否为空对我来说似乎也有点奇怪 | full 通知所有等待线程。有什么想法吗?
提前致谢。
最佳答案
我现在知道这是一个老问题了,但是在阅读了问题和答案之后我忍不住了,我希望你觉得这个有用。
关于在通知其他等待线程之前检查队列实际上是满的还是空的,你遗漏了一些方法 put (T t)
和 T get()
都是synchronized
方法,意味着一次只有一个线程可以进入这些方法中的一个,但这并不妨碍它们一起工作,所以如果线程-a 进入了 put (T t)
方法另一个线程-b 仍然可以在线程-a 退出之前进入并开始执行 T get()
方法中的指令 put (T t)
,因此这种双重检查
设计将使开发人员感到更安全一点,因为您无法知道 future 是否会或何时会发生 cpu 上下文切换。
更好和更推荐的方法是使用可重入锁
和条件
:
//我已经编辑了这个 link 的源代码
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;
}
使用这种方法不需要双重检查
,因为lock
对象在两种方法之间共享,这意味着只有一个线程a或b可以进入其中任何一个与创建不同监视器的同步方法不同,只有那些因为队列已满而等待的线程才会在有更多空间时得到通知,对于因为队列为空而等待的线程也是如此,这将导致更好的 cpu利用。
你可以在源代码中找到更详细的示例 here
关于java - 在 Java 中实现自己的阻塞队列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20110013/