在一个使用BlockingQueue
的应用程序中,我面临着一个新的需求,这个需求只能通过迭代队列中的元素来实现(提供关于队列中元素当前状态的信息)。
根据API Javadoc
,只有BlockingQueue实现的排队方法需要是线程安全的。Other API methods
(例如,从Collection interface
继承的那些)不能同时使用,尽管我不确定这是否也适用于纯粹的读访问...
我可以安全地使用iterator() WITHOUT altering the producer/consumer threads
吗?它通常可以在任何时候与队列交互。我不需要100% consistent iteration
(在迭代队列时是否看到添加/删除的元素并不重要),但我不想以讨厌的ConcurrentModificationExceptions
结束。
请注意,应用程序当前使用的是LinkedBlockingQueue
,但我可以自由选择任何其他(unbounded) BlockingQueue implementation
(包括free open-source third-party implementations
)。此外,我不想依赖于将来可能会损坏的东西,所以我希望一个解决方案符合API
,而不仅仅是碰巧与current JRE
一起工作。
2条答案
按热度按时间svmlkihl1#
实际上,Java 8 javadoc for
BlockingQueue
声明如下:BlockingQueue
实现是线程安全的。javadoc中没有说明1这仅适用于
BlockingQueue
API本身中指定的方法。我可以安全地使用iterator()而不改变生产者/消费者线程吗?生产者/消费者线程通常可以在任何时候与队列交互。
基本上是的,
Iterator
在面对并发修改时的行为在实现类javadocs中指定,对于LinkedBlockingQueue
,javadoc指定iterator()
返回的Iterator
是弱一致的,这意味着(例如)如果队列在迭代过程中被修改,应用程序将不会获得ConcurrentModificationException
,但是迭代过程不保证看到所有队列条目。1 -javadoc提到批量操作可能是非原子的,但非原子并不意味着非线程安全,这里的意思是其他线程可能观察到队列的状态,其中一些条目已经添加(或删除,或其他),而其他条目还没有。
@约翰·温特警告:
请记住,这是从Java 8开始的,可以更改。
如果Oracle决定改变javadoc* 中指定的行为,这将是迁移的障碍。过去的历史表明Sun / Oracle避免做这种事情。(尽管这并不意味着它不会发生。)
jv4diomz2#
是的,你可以迭代整个队列。看看
LinkedBlockingQueue
和ArrayBlockingQueue
的实现,你确实有一个副作用。当构造和操作Iterator
时,有三个地方获得了全锁。1.施工期间
1.调用
next()
时1.调用
remove()
时请记住,这是从Java 8开始的,可以更改。
因此,您确实可以安全地进行迭代,但会影响
put
和offer
的性能。现在对于您的问题,
BlockingQueue
是否提供安全的迭代?答案是这取决于实现。将来可能会有一个BlockingQueue实现抛出UnsupportedOperationException
。