【问题标题】:How to restrict a Stream to run sequentially, and prevent it from running in parallel?如何限制 Stream 顺序运行,并防止它并行运行?
【发布时间】:2016-02-23 11:19:51
【问题描述】:

我有一个方法可以返回从自定义拆分器生成的流;分离器不安全。由于分离器不安全,并且它保持状态,我想防止它并行运行。有没有办法防止返回的流并行运行?

我找不到任何这样做的文档或示例。我确实在BaseStream 类上找到了sequential() 方法,但这似乎并不能阻止用户调用parallel() 来获得并行流。

【问题讨论】:

  • 您不需要拆分器来保证线程安全,也可以用于并行使用。流框架将为您管理线程安全。
  • 我的想法完全正确。该文档明确指出:尽管在并行算法中具有明显的实用性,但拆分器不应该是线程安全的
  • @JBNizet 您引用的完整句子是“尽管拆分器在并行算法中具有明显的实用性,但不期望拆分器是线程安全的;相反,使用拆分器的并行算法的实现应确保spliterator 一次只能由一个线程使用。"。我关心的是那句话的后半部分,我找不到任何说明并行流将按顺序访问拆分器的文档。
  • @MikeRylander 该文档适用于编写自己的流(如实用程序)的人;您可以放心地假设流库本身已正确实现。您可以放心地假设 JDK 遵循自己的建议。此外,在 spliterators 中内置的 JDK 都不是线程安全的,如果这会破坏并行流的话,这会破坏并行流的意义。
  • @LouisWasserman,如果拆分过程创建的对等点不改变共享状态,拆分器可能不关心线程安全。这并非总是如此。 Here 在 JDK-9 中的 Spliterator 示例,它维护共享状态(AtomicBoolean 变量)。有时我会编写更复杂的拆分器,它们应该非常关心线程安全。

标签: java java-stream spliterator


【解决方案1】:

默认情况下,流是同步的,所以如果你正确记录你的库,这个问题就无关紧要了。用户有责任确保他们使用的库是线程安全的。只是表明你的不是。

如果您可以在服务器端发送线程ID并通过API在客户端接收它,有一种方法可以检查线程:

Thread.currentThread().getId()

并在收到时将其与您的线程 ID 进行比较。抛出 Exception 并带有明确的错误消息“不是线程安全的!”当它们不同时。

【讨论】:

    【解决方案2】:

    并行流调用拆分器的trySplit() 方法将您的任务拆分为多个部分。是absolutely legittrySplit() 返回null 说“我拒绝分裂”。在这种情况下,即使 .parallel() 被显式调用,从拆分器创建的流也会按顺序执行。

    但是,通常您可以提供至少有限的并行性来扩展 AbstractSpliterator 类。它提供默认的trySplit() 实现,它读取一些调用您的tryAdvance() 方法的输入元素,将它们存储到数组中并返回该数组上的拆分器,因此这部分可以单独处理并且完全独立于您的拆分器。这是“穷人”并行化,但如果下游管道操作很耗时,仍然可以提高速度。

    最后请注意,在大多数简单情况下,Spliterator 实现不应该是线程安全的。如果您提供自己的高效trySplit() 实现,则可以保证原始拆分器和新创建的拆分器将以完全独立的方式进行处理。所以如果拆分后不修改前缀和后缀拆分器中的共享状态,则不必关心线程安全。

    【讨论】:

    • 谢谢,trySplit() return null 确实会阻止并行执行。您是否知道任何说明它将使用trySplit() 来实现并行性的流文档?
    • @MikeRylander,Spliterator 类文档说:“Spliterator 还可以将其某些元素(使用 trySplit())划分为另一个 Spliterator,用于可能的并行操作。操作使用无法拆分或以高度不平衡或低效的方式拆分的 Spliterator 不太可能从并行性中受益。”
    猜你喜欢
    • 1970-01-01
    • 2019-09-18
    • 2015-02-10
    • 1970-01-01
    • 2015-02-25
    • 1970-01-01
    • 1970-01-01
    • 2020-08-13
    相关资源
    最近更新 更多