在java中实现自己的阻塞队列

我知道这个问题之前已被多次询问和回答,但我无法弄清楚互联网上的例子,比如这个或那个 。

这两个解决方案都检查阻塞队列的数组/队列/链表的空白,以便在get()方法中通知put()方法中的所有等待线程,反之亦然。 第二个链接中的评论强调了这种情况,并提到这不是必要的。

所以问题是; 检查队列是否为空,对我来说似乎有点奇怪 完全通知所有等待的线程。 有任何想法吗?

提前致谢。

我知道这是一个古老的问题,但在阅读了问题和答案后,我无法帮助自己,我希望你觉得这很有用。

关于在通知其他等待线程之前检查队列是否实际已满或为空,你会遗漏一些方法put (T t)T get()都是synchronized方法,这意味着只有一个线程可以输入其中一个方法一次,但这不会阻止它们一起工作,所以如果一个线程-a已经输入put (T t)方法,另一个线程-b仍然可以进入并开始执行T get()方法中的指令a已退出put (T t) ,因此这种double-checking设计将使开发人员感觉更安全,因为您无法知道未来的cpu上下文切换是否会发生。

更好和更推荐的方法是使用Reentrant LocksConditions

//我已经从这个链接编辑了源代码

 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利用率。 你可以在这里找到更详细的源代码示例

我认为逻辑上在notifyAll()之前进行额外的检查是没有害处的。

一旦从队列中放入/获取内容,您就可以简单地notifyAll() 。 一切都会工作,你的代码更短。 但是,在调用notifyAll()之前,检查是否有人可能正在等待(通过检查是否命中队列边界)也没有任何危害。 这个额外的逻辑节省了不必要的notifyAll()调用。

这取决于您是否需要更简洁,更清晰的代码,或者您希望代码更有效地运行。 (没有查看notifyAll()的实现。如果没有人等待是一个便宜的操作,那么额外检查的性能提升可能并不明显)

作者使用notifyAll()的原因很简单:他们不知道是否有必要,所以他们决定选择“更安全”的选项。

在上面的例子中,仅为每个添加的单个元素调用notify()就足够了,在所有情况下只能提供单个线程等待。

这变得更加明显,如果您的队列也可以选择在一个步骤中添加多个元素,如addAll(Collection list) ,因为在这种情况下可以提供等待空列表的多个线程,确切地说:添加了许multithreading作为元素。

然而, notifyAll()在特殊的单元素情况下会产生额外的开销,因为许multithreading被不必要地唤醒,因此必须再次进入hibernate状态,同时阻止队列访问。 因此,使用notify()替换notifyAll()可以提高此特殊情况下的速度。

但是之后根本没有使用wait / notify和synchronized,而是使用并发包会比任何智能等待/通知实现所能获得的速度提高很多。