java 并发迭代BlockingQueue

hgncfbus  于 2023-02-28  发布在  Java
关注(0)|答案(2)|浏览(103)

在一个使用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一起工作。

svmlkihl

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避免做这种事情。(尽管这并不意味着它不会发生。)

jv4diomz

jv4diomz2#

是的,你可以迭代整个队列。看看LinkedBlockingQueueArrayBlockingQueue的实现,你确实有一个副作用。当构造和操作Iterator时,有三个地方获得了全锁。
1.施工期间
1.调用next()
1.调用remove()
请记住,这是从Java 8开始的,可以更改。
因此,您确实可以安全地进行迭代,但会影响putoffer的性能。
现在对于您的问题,BlockingQueue是否提供安全的迭代?答案是这取决于实现。将来可能会有一个BlockingQueue实现抛出UnsupportedOperationException

相关问题