我正在使用Java 8 Streams。我有一个自定义函数foo()
,它产生一个对象,我想并行传输它创建的对象。我知道foo()
不是线程安全的。
如果我写Stream.generate(foo).parallel()
,是否会以异步方式调用foo()
?即将对象串行生成并传递给并行线程,还是多个线程根据需要通过调用foo()
来生成对象?
答案 0 :(得分:5)
您可以通过快速实验观察供应商的多个线程:
Stream.generate(() -> Thread.currentThread().getId())
.parallel()
.limit(100000)
.distinct()
.forEach(System.out::println);
答案 1 :(得分:3)
虽然数据争用不是保证行为,但以下代码
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的数字,证明当供应商不是线程安全时,确实可能发生缺失的更新。
请注意,供应商也可能会查询比结果评估所需的元素更多的元素。 E.g。
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个不同的数字。