【问题标题】:Is it safe to stream a concurrent collection while it is modified externally?在外部修改并发集合时流式传输它是否安全?
【发布时间】:2018-06-08 07:17:37
【问题描述】:

我有一个ConcurrentLinkedQueue,它可以被多个线程访问;其中的对象是不可变的。在一个线程中,我需要数据的快照,我通过调用stream 来完成。安全吗?我知道non-interference 的要求,但它似乎是在谈论对流操作之一的修改(“源可能不是并发的流管道永远不应该修改流的数据源” ),不一定是外部的。此外,ConcurrentLinkedQueue 是为并发访问而设计的,所以就是这样。

【问题讨论】:

  • “快照”将是终端操作将观察到的任何状态。因此,您的终端操作可能会“看到”这是最后一个元素,并通过 peek 获取它;但在那之后(假设在终端操作完成之前),有人可能会添加更多元素。这就是你对弱一致性迭代器的期望......

标签: java multithreading concurrency java-8 java-stream


【解决方案1】:

来自您提供的链接中的文档

对于大多数数据源,防止干扰意味着确保 在流的执行过程中根本不修改数据源 管道。值得注意的例外是其来源为 并发集合,专门设计用于处理 并发修改。并发流源是那些 Spliterator 报告 CONCURRENT 特征

来自 SplitIterator 的文档(其 CONCURRENT 特征)

静态最终 int 并发

表示元素来源可能安全的特征值 同时修改(允许添加、替换和/或 删除)由多个线程在没有外部同步的情况下进行。如果是这样的话, Spliterator 应有关于 遍历期间修改的影响。

这是 Collection 接口流方法的实现(在 ConcurrentLinkedQueue 中没有被覆盖)

default Stream<E> stream() {
        return StreamSupport.stream(spliterator(), false);
}

只要 ConcurrentLinkedQueue 使用 CONCURRENT SplitIterator(确实如此),我假设您可以使用 stream() 安全地迭代您的 ConcurrentLinkedQueue。

【讨论】:

  • 我发现有趣的是,即使通过并发,流也不是并行的。此外,对集合的外部更改是否对流可见?
  • @AbhijitSarkar 如果您使用parallelStream(),流将是并行的。或stream().parallel()。那是流管道的模式,与源无关。对流的外部更改的可见性与为迭代器指定的相同,即 weakly consistent 对于大多数并发集合。
  • ...因为stream()实现委托给spliterator(),你必须看看the specific spliterator() implementation
  • @Holger 我不明白你关于并行的评论。 StreamSupport.stream 的第二个参数是parallel,也就是上面的false
  • @AbhijitSarkar 这是stream() 的实现。如果您想要并行流,请使用parallelStream()parallelStream() 的实现看起来完全一样,除了使用true 而不是false。除此之外,您可以通过在流上调用parallel()sequential() 来更改流的模式。集合的类型,即是否并发,与流的执行模式无关。
猜你喜欢
  • 2021-07-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-22
  • 1970-01-01
  • 1970-01-01
  • 2020-09-13
  • 2014-03-29
相关资源
最近更新 更多