在外部修改并发集合时,流式传输是否安全?

Abh*_*kar 8 java concurrency multithreading java-8 java-stream

我有一个ConcurrentLinkedQueue由多个线程访问的; 其中的对象是不可变的.在一个线程中,我需要一个数据快照,我正在通过调用stream它来完成.安全吗?我知道无干扰要求,但它似乎是在讨论从其中一个流操作(" 源流可能不是并发的流管道永远不应修改流的数据源 ")的修改,而不一定是外部的.此外,它ConcurrentLinkedQueue是专为并发访问而设计的,所以就是这样.

小智 9

从您提供的链接文档中

对于大多数数据源,防止干扰意味着确保在流管道的执行期间根本不修改数据源.值得注意的例外是其源是并发集合的流,这些集合专门用于处理并发修改.并发流源是Spliterator报告CONCURRENT特性的源

从SplitIterator的文档(其CONCURRENT特性)

static final int CONCURRENT

表示可以在没有外部同步的情况下由多个线程安全地同时修改元素源(允许添加,替换和/或删除)的特征值.如果是这样,Spliterator应该有一个关于遍历期间修改影响的书面政策.

这是Collection接口流方法的实现(在ConcurrentLinkedQueue中没有重写)

default Stream<E> stream() {
        return StreamSupport.stream(spliterator(), false);
}
Run Code Online (Sandbox Code Playgroud)

因此,只要ConcurrentLinkedQueue使用CONCURRENT SplitIterator(它确实如此),我认为您可以使用stream()安全地迭代ConcurrentLinkedQueue.

  • @AbhijitSarkar如果使用`parallelStream()`,流将是并行的.或者`stream().parallel()`.这是流管道的模式,与源无关.流的外部更改的可见性与为迭代器指定的相同,即[*弱一致*](https://docs.oracle.com/javase/9​​/docs/api/java/util/concurrent/package -summary.html #Weakly)适用于大多数并发集合. (2认同)
  • @AbhijitSarkar是`stream()`的实现.如果需要并行流,请使用`parallelStream()`.`parallelStream()`的实现看起来完全一样,除了使用`true`而不是`false`.除此之外,您可以通过在流上调用`parallel()`或`sequential()`来更改流的模式.集合的类型,即是否并发,对流的执行模式无关紧要. (2认同)