在使用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
一起工作。
答案 0 :(得分:5)
实际上,BlockingQueue
的Java 8 javadoc声明了这一点:
BlockingQueue
实现是线程安全的。
javadoc中没有任何内容说 1 ,这只适用于BlockingQueue
API本身中指定的方法。
我可以安全地使用iterator()而无需改变通常可能随时与队列交互的生产者/消费者线程吗?
基本上,是的。面对并发修改时Iterator
的行为在实现类javadocs中指定。对于LinkedBlockingQueue
,javadoc指定Iterator
返回的iterator()
为weakly consistent。这意味着(例如)如果队列在迭代时被修改,您的应用程序将不会获得ConcurrentModificationException
,但是不能保证迭代看到所有队列条目。
1 - javadoc提到批量操作可能是非原子操作,但非原子操作并不意味着非线程安全。这意味着其他一些线程可能会在某些条目被添加(或删除,或其他)的状态下观察队列,而其他线程则没有。
@John Vint警告说:
请记住,这与Java 8一样,可以更改。
如果Oracle决定改变javadoc 中指定的行为,那将成为迁移的障碍。过去的历史表明Sun / Oracle避免做那种事情。
答案 1 :(得分:3)
是的,您可以遍历整个队列。查看LinkedBlockingQueue
和ArrayBlockingQueue
实现,您会产生副作用。在构造和操作Iterator
时,有三个地方可以获得完全锁定。
next()
remove()
请记住,这与Java 8一样,可以更改。
所以,是的,你确实可以安全地进行迭代,但是你会影响put
和offer
的性能。
现在针对您的问题,BlockingQueue
是否提供安全迭代?答案取决于实施。未来的BlockingQueue实现可能会抛出UnsupportedOperationException
。