繁体   English   中英

对于Stream.generate(foo).parallel(),foo必须是线程安全的吗?

[英]For Stream.generate(foo).parallel(), does foo have to be thread safe?

我正在使用Java 8 Streams。 我有一个自定义函数foo() ,它产生一个对象,我想并行传输它创建的对象。 我知道foo()不是线程安全的。

如果我写Stream.generate(foo).parallel() ,会以异步方式调用foo()吗? 即,对象是串行生成的,并传递给并行线程,还是多个线程通过调用foo()根据需要生成对象?

如您可以通过快速实验观察到的,将从多个线程调用供应商:

Stream.generate(() -> Thread.currentThread().getId())
    .parallel()
    .limit(100000)
    .distinct()
    .forEach(System.out::println);

虽然数据争用不是保证行为,但以下代码

System.out.println(
    Stream.generate(new Supplier<Integer>() {
        int i; @Override public Integer get() { return i++; }
    }).parallel()
      .limit(10_000)
      .collect(BitSet::new, BitSet::set, BitSet::or)
      .cardinality()
);

在我的环境中可重复打印小于10,000的数字,证明当供应商不是线程安全时,确实可能发生缺失更新。

请注意,供应商也可能需要查询比结果评估所需的元素更多的元素。 例如

LongAdder adder = new LongAdder();
System.out.println(
    Stream.generate(new Supplier<Integer>() {
        int i; @Override public Integer get() { adder.increment(); return i++; }
    }).parallel()
      .limit(10_000)
      .collect(BitSet::new, BitSet::set, BitSet::or)
      .cardinality()
);
System.out.println("queried "+adder+" times");

通常报告大量超过10,000的查询,同时,由于数据竞争,结果报告少于10,000个不同的元素。

使供应商线程安全,将结果更改为10,000个不同元素的正确数量,但供应商仍可查询超过10,000次,因此,结果不能保证包含0到9,999之间的数字,因为流通过generate创建的是无序的 ,因此可以使用来自供应商的任何10,000个不同的数字。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM