Thread.yield()有更好的解决方案吗?

我创建了一个扩展ArrayBlockingQueue的CloseableBlockingQueue:

private static class CloseableBlockingQueue extends ArrayBlockingQueue { // Flag indicates closed state. private volatile boolean closed = false; public CloseableBlockingQueue(int queueLength) { super(queueLength); } /*** * Shortcut to do nothing if closed. */ @Override public boolean offer(E e) { return closed ? true : super.offer(e); } /*** * Shortcut to do nothing if closed. */ @Override public void put(E e) throws InterruptedException { if (!closed) { super.put(e); } } /*** * Shortcut to do nothing if closed. */ @Override public E poll() { return closed ? null : super.poll(); } /*** * Shortcut to do nothing if closed. * @throws InterruptedException */ @Override public E poll(long l, TimeUnit tu) throws InterruptedException { return closed ? null : super.poll(l, tu); } /*** * Mark me as closed and clear the queue. */ void close() { closed = true; // There could be more threads blocking on my queue than there are slots // in the queue. We therefore MUST loop. do { // so keep clearing clear(); /* Let others in ... more specifically, any collectors blocked on the * queue should now unblock and finish their put. * * Subsequent puts should shortcut but it is the waiting ones I need * to clear. */ Thread.yield(); /* Debug code. // Did yield achieve? if (!super.isEmpty()) { * This DOES report success. log("! Thread.yield() successful"); } * */ // Until all are done. } while (!super.isEmpty()); } /*** * isClosed * * @return true if closed. */ boolean isClosed() { return closed; } } 

我关注的是密切方法,它试图重新启动队列中阻塞的任何线程。 我使用Thread.yield()来尝试,但是我看到了一些引用,这些引用表明这种技术可能并不总是有效,因为无法保证在收益期间任何其他被阻塞的线程都会被唤醒。

该队列用于将多个线程的输出集中到单个流中。 与队列中的插槽相比,可以轻松地提供更multithreading,因此队列很可能已满并且当它关闭时,有几个线程阻塞它。

我欢迎你的想法。

添加

感谢Tom的建议,我已经重构:

  • 保留可能阻塞的所有线程的集合。
  • 关闭时,中断所有这些。

BTW:由于线程集合主要用于添加对象并几乎立即删除相同的对象,因此我从http://www.java2s.com/Code/Java/CollectionsANN-Structure/获取了Doug Lea令人印象深刻的ConcurrentDoublyLinkedList副本。 ConcurrentDoublyLinkedList.htm并添加了几个方法,让我可以保持添加的节点。 然后去除应该是O(1)而不是O(n)。

保罗

我认为yield()根本不会影响队列中阻塞的线程。

如果你可以跟踪等待的线程(鉴于你正在包装阻塞方法,应该是直截了当的)。 你可以在关闭时调用它们的interrupt()。

看到这个问题: ArrayBlockingQueue – 如何“中断”正在使用.take()方法的线程

而不是yield-while-check循环,使用wait/notifyAll()或者最好使用util.concurrent包中的一个同步原语,例如CountDownLatch 。 将对象放在队列的末尾,在处理时触发通知。 使调用线程(close方法)等待此通知。 它会一直睡到队列耗尽。

我会把毒丸放入队列。 例如null。 当等待线程获得药丸时,它会将其放回队列中。

 E pill = null; void close() { closed = true; clear(); while(!offer(pill)); // will wake one thread. } public E poll() { if (closed) return null; E e = super.poll(); if (e == pill) add(e); // will wake one thread. return e; }