在Java 8中,可以设置一个自定义forkJoinPool,以供并行流而不是公共池使用。
forkJoinPool.submit(() -> list.parallelStream().forEach(x ->{...} ))
我的问题是,它在技术上是如何发生的?
流不知道以任何方式将其提交到自定义forkJoinpool,并且无法直接访问它。那么最终如何使用正确的线程来处理流的任务?
我尝试查看源代码,但无济于事。我最好的猜测是在提交时在某个时候设置了一些threadLocal变量,然后稍后由流使用。如果是这样,为什么语言开发人员会选择这种方式来实现该行为,而不是将依赖项注入到流中呢?
谢谢!
答案 0 :(得分:1)
java.util.stream.ForEachOps.ForEachOp#evaluateParallel
方法调用invoke()
:
@Override public <S> Void evaluateParallel(PipelineHelper<T> helper, Spliterator<S> spliterator) { if (ordered) new ForEachOrderedTask<>(helper, spliterator, this).invoke(); else new ForEachTask<>(helper, spliterator, helper.wrapSink(this)).invoke(); return null; }
依次调用java.util.concurrent.ForkJoinTask#doInvoke
:
private int doInvoke() { int s; Thread t; ForkJoinWorkerThread wt; return (s = doExec()) < 0 ? s : ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ? (wt = (ForkJoinWorkerThread)t).pool. awaitJoin(wt.workQueue, this, 0L) : externalAwaitDone(); }
如上述方法所示,它使用Thread.currentThread()
查找当前线程。
然后它像.pool
一样使用(wt = (ForkJoinWorkerThread)t).pool
字段,它提供了该线程在其中运行的当前池:
public class ForkJoinWorkerThread extends Thread { final ForkJoinPool pool; // the pool this thread works in
答案 1 :(得分:1)
根据我读过的代码,该决定仅基于触发计算的初始线程(仅在方法ForkJoinTask::fork
内 做出),该方法实际上会检查线程触发了这一点(也在其文档中):
Thread.currentThread()) instanceof ForkJoinWorkerThread
因此,如果ForkJoinWorkerThread
的实例已启动此操作(这是通过自定义ForkJoinPool
获得的结果),请使用池中已存在的任何内容运行此任务;否则(如果它是另一个线程,而不是ForkJoinWorkerThread
的实例),请使用:
ForkJoinPool.common.externalPush(this);
有趣的是ForkJoinWorkerThread
实际上是public
类,因此您可以在其实例内部开始计算,但仍使用其他池;尽管我还没有尝试过。