为什么说Java8的Stream并行流底层使用了Fork/Join框架
先说结论
Stream 是支持串行和并行执行这两种方式的
如何开启并行?
- 调用parallel方法即可
Stream.of(1, 2, 3, 4, 5).parallel()
先写一个Java8Stream并行流的demo,如下:
import java.util.stream.Stream;
public class AtomicIntegerArrayTest {
public static void main(String[] args) {
Stream.of(1, 2, 3, 4, 5).parallel().reduce((a, b) -> {
return a + b;
}).ifPresent(System.out::println);
}
}
以上的结果是1-5的累加值,如下:
先看看parallel()方法,进入相关的类AbstractPipeline中,如下:
abstract class AbstractPipeline<E_IN, E_OUT, S extends BaseStream<E_OUT, S>>
extends PipelineHelper<E_OUT> implements BaseStream<E_OUT, S> {
private final AbstractPipeline sourceStage;
private boolean parallel;
@Override
@SuppressWarnings("unchecked")
public final S parallel() {
sourceStage.parallel = true;
return (S) this;
}
}
可以发现parallel()方法做的事很简单,就是标记个并行的标记,设置为true。
那么接下来看看reduce()方法:
abstract class ReferencePipeline<P_IN, P_OUT>
extends AbstractPipeline<P_IN, P_OUT, Stream<P_OUT>>
implements Stream<P_OUT> {
@Override
public final Optional<P_OUT> reduce(BinaryOperator<P_OUT> accumulator) {
return evaluate(ReduceOps.makeRef(accumulator));
}
}
接着evaluate()方法跟下去,如下:
abstract class AbstractPipeline<E_IN, E_OUT, S extends BaseStream<E_OUT, S>>
extends PipelineHelper<E_OUT> implements BaseStream<E_OUT, S> {
final <R> R evaluate(TerminalOp<E_OUT, R> terminalOp) {
assert getOutputShape() == terminalOp.inputShape();
if (linkedOrConsumed)
throw new IllegalStateException(MSG_STREAM_LINKED);
linkedOrConsumed = true;
return isParallel()
? terminalOp.evaluateParallel(this, sourceSpliterator(terminalOp.getOpFlags()))
: terminalOp.evaluateSequential(this, sourceSpliterator(terminalOp.getOpFlags()));
}
@Override
public final boolean isParallel() {
return sourceStage.parallel;
}
}
从以上的三元表达式中可以得出,调用isParallel()方法会得到之前通过parallel()方法设置的true值,然后就会执行terminalOp.evaluateParallel(this, sourceSpliterator(terminalOp.getOpFlags()))方法,所以接着跟进看看evaluateParallel()方法。
首先会进入TerminalOp接口类,如下:
interface TerminalOp<E_IN, R> {
default <P_IN> R evaluateParallel(PipelineHelper<E_IN> helper,
Spliterator<P_IN> spliterator) {
if (Tripwire.ENABLED)
Tripwire.trip(getClass(), "{0} triggering TerminalOp.evaluateParallel serial default");
return evaluateSequential(helper, spliterator);
}
}
会发现这是接口的默认方法,由于使用的是reduce方法,所以看看其相应的实现类对evaluateParallel()方法的实现,如下:
final class ReduceOps {
@Override
public <P_IN> R evaluateParallel(PipelineHelper
Spliterator<P_IN> spliterator) {
return new ReduceTask<>(this, helper, spliterator).invoke().get();
}
}
这时候会发现,该方法中new了一个ReduceTask类,然后调用了它的invoke()方法,看看ReduceTask类相关信息,最后会发现它的继承链是这样的:
`ReduceTask->AbstractTask->CountedCompleter->ForkJoinTask`
1
可以发现最终跟到了ForkJoinTask类中,然后点击跟进invoke()方法,会发现调用的其实是ForkJoinTask()的invoke()方法,该方法是final修饰的,子类无法重写,如下:
public final V invoke() {
int s;
if ((s = doInvoke() & DONE_MASK) != NORMAL)
reportException(s);
return getRawResult();
}
总结
通过以上几步源码的跟踪,可以证明Java8的Stream并行流底层确实是使用了Fork/Join框架。
java新手自学群 626070845
java/springboot/hadoop/JVM 群 4915800
Hadoop/mongodb(搭建/开发/运维)Q群481975850
GOLang Q1群:6848027
GOLang Q2群:450509103
GOLang Q3群:436173132
GOLang Q4群:141984758
GOLang Q5群:215535604
C/C++/QT群 1414577
单片机嵌入式/电子电路入门群群 306312845
MUD/LIB/交流群 391486684
Electron/koa/Nodejs/express 214737701
大前端群vue/js/ts 165150391
操作系统研发群:15375777
汇编/辅助/破解新手群:755783453
大数据 elasticsearch 群 481975850
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。