以Fibonacci series為例探討Fork/Join的compute和join
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;
public class Main {
public static void main(String[] args) {
int poolSize = Runtime.getRuntime().availableProcessors();
System.out.println("poolSize: " + poolSize);
/**
* ...
*/
System.out.println("result: " + result);
}
}
class Fibonacci extends RecursiveTask<Integer> {
final int n;
private String path;
public Fibonacci(int n, String path) {
this.n = n;
this.path = path;
}
@Override
protected Integer compute() {
this.log("[Start]");
if (n <= 1) {
this.log("[ End ]");
return n;
}
/**
* ...
*/
}
private void log(String prefix) {
StringBuilder buf = new StringBuilder(prefix);
buf.append(" inPool: ").append(inForkJoinPool());
buf.append(" queuedTaskCount: ").append(getQueuedTaskCount());
buf.append(" thread: ").append(Thread.currentThread());
buf.append(" path: ").append(this.path);
System.out.println(buf.toString());
}
}
ForkJoinPool
利用ForkJoinPool來執行task
Main寫法參考如下
ForkJoinPool pool = new ForkJoinPool(poolSize);
Integer result = pool.invoke(new Fibonacci(5, "5"));
f2.compute() + f1.join()
參考クラスRecursiveTask
Fibonacci範例compute實作如下
Fibonacci f1 = new Fibonacci(n - 1, path + " -> " + (n - 1));
f1.fork();
Fibonacci f2 = new Fibonacci(n - 2, path + " -> " + (n - 2));
this.log("[ End ]");
return f2.compute() + f1.join();
輸出結果如下(每次結果可能都不同)
poolSize: 4
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5
[ End ] inPool: true queuedTaskCount: 1 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5
[Start] inPool: true queuedTaskCount: 1 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5 -> 3
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-2,5,main] path: 5 -> 4
[ End ] inPool: true queuedTaskCount: 1 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5 -> 3
[Start] inPool: true queuedTaskCount: 1 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5 -> 3 -> 1
[ End ] inPool: true queuedTaskCount: 1 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5 -> 3 -> 1
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-3,5,main] path: 5 -> 3 -> 2
[ End ] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-3,5,main] path: 5 -> 3 -> 2
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-3,5,main] path: 5 -> 3 -> 2 -> 0
[ End ] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-3,5,main] path: 5 -> 3 -> 2 -> 0
[ End ] inPool: true queuedTaskCount: 1 thread: Thread[ForkJoinPool-1-worker-2,5,main] path: 5 -> 4
[Start] inPool: true queuedTaskCount: 1 thread: Thread[ForkJoinPool-1-worker-2,5,main] path: 5 -> 4 -> 2
[ End ] inPool: true queuedTaskCount: 2 thread: Thread[ForkJoinPool-1-worker-2,5,main] path: 5 -> 4 -> 2
[Start] inPool: true queuedTaskCount: 2 thread: Thread[ForkJoinPool-1-worker-2,5,main] path: 5 -> 4 -> 2 -> 0
[ End ] inPool: true queuedTaskCount: 2 thread: Thread[ForkJoinPool-1-worker-2,5,main] path: 5 -> 4 -> 2 -> 0
[Start] inPool: true queuedTaskCount: 1 thread: Thread[ForkJoinPool-1-worker-2,5,main] path: 5 -> 4 -> 2 -> 1
[ End ] inPool: true queuedTaskCount: 1 thread: Thread[ForkJoinPool-1-worker-2,5,main] path: 5 -> 4 -> 2 -> 1
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-2,5,main] path: 5 -> 4 -> 3
[ End ] inPool: true queuedTaskCount: 1 thread: Thread[ForkJoinPool-1-worker-2,5,main] path: 5 -> 4 -> 3
[Start] inPool: true queuedTaskCount: 1 thread: Thread[ForkJoinPool-1-worker-2,5,main] path: 5 -> 4 -> 3 -> 1
[ End ] inPool: true queuedTaskCount: 1 thread: Thread[ForkJoinPool-1-worker-2,5,main] path: 5 -> 4 -> 3 -> 1
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-2,5,main] path: 5 -> 4 -> 3 -> 2
[ End ] inPool: true queuedTaskCount: 1 thread: Thread[ForkJoinPool-1-worker-2,5,main] path: 5 -> 4 -> 3 -> 2
[Start] inPool: true queuedTaskCount: 1 thread: Thread[ForkJoinPool-1-worker-2,5,main] path: 5 -> 4 -> 3 -> 2 -> 0
[ End ] inPool: true queuedTaskCount: 1 thread: Thread[ForkJoinPool-1-worker-2,5,main] path: 5 -> 4 -> 3 -> 2 -> 0
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-2,5,main] path: 5 -> 4 -> 3 -> 2 -> 1
[ End ] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-2,5,main] path: 5 -> 4 -> 3 -> 2 -> 1
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5 -> 3 -> 2 -> 1
[ End ] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5 -> 3 -> 2 -> 1
result: 5
由以上結果來說明f2 compute()
和f1 join()
差異
pool.invoke會從pool取得thread[ForkJoinPool-1-worker-1]
之後
執行new Fibonacci(5, "5")這個task的compute方法
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5
因為5沒有<=1所以拆解
f1 = new Fibonacci(4, ...)並且執行fork將f1放入[ForkJoinPool-1-worker-1]
的workQuere
queuedTaskCount為1
public final ForkJoinTask<V> fork() {
Thread t;
if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread)
((ForkJoinWorkerThread)t).workQueue.push(this);
else
ForkJoinPool.common.externalPush(this);
return this;
}
f2 = new Fibonacci(3, ...)
[ End ] inPool: true queuedTaskCount: 1 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5
return執行f2的compute方法
所以它會利用現在這個thread[ForkJoinPool-1-worker-1]
執行Fibonacci(3, ...)的compute方法(path: 5 -> 3)
[Start] inPool: true queuedTaskCount: 1 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5 -> 3
return另一方面也執行f1的join方法
因為work-stealing queue的特性
pool裡的thread[ForkJoinPool-1-worker-2]
搶走[ForkJoinPool-1-worker-1]
workQuere的task(path: 5 -> 4)執行compute方法直到完成可以join為止
private int doJoin() {
int s; Thread t; ForkJoinWorkerThread wt; ForkJoinPool.WorkQueue w;
return (s = status) < 0 ? s :
((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ?
(w = (wt = (ForkJoinWorkerThread)t).workQueue).
tryUnpush(this) && (s = doExec()) < 0 ? s :
wt.pool.awaitJoin(w, this, 0L) :
externalAwaitDone();
}
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-2,5,main] path: 5 -> 4
3沒有<=1所以繼續拆解
f1 = new Fibonacci(2, ...)並且執行fork將f1放入[ForkJoinPool-1-worker-1]的workQuere
queuedTaskCount為1
f2 = new Fibonacci(1, ...)
[ End ] inPool: true queuedTaskCount: 1 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5 -> 3
[Start] inPool: true queuedTaskCount: 1 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5 -> 3 -> 1
1<=1所以return 1
[ End ] inPool: true queuedTaskCount: 1 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5 -> 3 -> 1
其餘請同上類推...
f2.join() + f1.join()
Fibonacci範例compute實作如下
Fibonacci f1 = new Fibonacci(n - 1, path + " -> " + (n - 1));
f1.fork();
Fibonacci f2 = new Fibonacci(n - 2, path + " -> " + (n - 2));
f2.fork();
this.log("[ End ]");
return f2.join() + f1.join();
輸出結果如下(每次結果可能都不同)
poolSize: 4
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5
[ End ] inPool: true queuedTaskCount: 2 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5 -> 3
[ End ] inPool: true queuedTaskCount: 2 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5 -> 3
[Start] inPool: true queuedTaskCount: 1 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5 -> 3 -> 1
[ End ] inPool: true queuedTaskCount: 1 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5 -> 3 -> 1
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-3,5,main] path: 5 -> 3 -> 2
[ End ] inPool: true queuedTaskCount: 1 thread: Thread[ForkJoinPool-1-worker-3,5,main] path: 5 -> 3 -> 2
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-0,5,main] path: 5 -> 3 -> 2 -> 0
[ End ] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-0,5,main] path: 5 -> 3 -> 2 -> 0
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-2,5,main] path: 5 -> 4
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5 -> 3 -> 2 -> 1
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-0,5,main] path: 5 -> 4 -> 3
[ End ] inPool: true queuedTaskCount: 2 thread: Thread[ForkJoinPool-1-worker-2,5,main] path: 5 -> 4
[ End ] inPool: true queuedTaskCount: 2 thread: Thread[ForkJoinPool-1-worker-0,5,main] path: 5 -> 4 -> 3
[ End ] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5 -> 3 -> 2 -> 1
[Start] inPool: true queuedTaskCount: 1 thread: Thread[ForkJoinPool-1-worker-0,5,main] path: 5 -> 4 -> 3 -> 1
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-2,5,main] path: 5 -> 4 -> 2
[ End ] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-0,5,main] path: 5 -> 4 -> 3 -> 1
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-3,5,main] path: 5 -> 4 -> 3 -> 2
[ End ] inPool: true queuedTaskCount: 2 thread: Thread[ForkJoinPool-1-worker-3,5,main] path: 5 -> 4 -> 3 -> 2
[Start] inPool: true queuedTaskCount: 1 thread: Thread[ForkJoinPool-1-worker-3,5,main] path: 5 -> 4 -> 3 -> 2 -> 0
[ End ] inPool: true queuedTaskCount: 1 thread: Thread[ForkJoinPool-1-worker-3,5,main] path: 5 -> 4 -> 3 -> 2 -> 0
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-3,5,main] path: 5 -> 4 -> 3 -> 2 -> 1
[ End ] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-3,5,main] path: 5 -> 4 -> 3 -> 2 -> 1
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-3,5,main] path: 5 -> 4 -> 2 -> 1
[ End ] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-3,5,main] path: 5 -> 4 -> 2 -> 1
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-3,5,main] path: 5 -> 4 -> 2 -> 0
[ End ] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-3,5,main] path: 5 -> 4 -> 2 -> 0
[ End ] inPool: true queuedTaskCount: 2 thread: Thread[ForkJoinPool-1-worker-2,5,main] path: 5 -> 4 -> 2
result: 5
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5
f1 = new Fibonacci(4, ...)並且執行fork將f1放入[ForkJoinPool-1-worker-1]
的workQuere
f2 = new Fibonacci(3, ...)並且執行fork將f2放入[ForkJoinPool-1-worker-1]
的workQuere
所以queuedTaskCount總數為2
[ End ] inPool: true queuedTaskCount: 2 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5
其餘請同上類推...
f2.compute() + f1.compute()
Fibonacci範例compute實作如下
Fibonacci f1 = new Fibonacci(n - 1, path + " -> " + (n - 1));
Fibonacci f2 = new Fibonacci(n - 2, path + " -> " + (n - 2));
this.log("[ End ]");
return f2.compute() + f1.compute();
輸出結果如下(每次結果都相同)
poolSize: 4
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5
[ End ] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5 -> 3
[ End ] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5 -> 3
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5 -> 3 -> 1
[ End ] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5 -> 3 -> 1
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5 -> 3 -> 2
[ End ] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5 -> 3 -> 2
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5 -> 3 -> 2 -> 0
[ End ] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5 -> 3 -> 2 -> 0
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5 -> 3 -> 2 -> 1
[ End ] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5 -> 3 -> 2 -> 1
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5 -> 4
[ End ] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5 -> 4
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5 -> 4 -> 2
[ End ] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5 -> 4 -> 2
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5 -> 4 -> 2 -> 0
[ End ] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5 -> 4 -> 2 -> 0
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5 -> 4 -> 2 -> 1
[ End ] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5 -> 4 -> 2 -> 1
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5 -> 4 -> 3
[ End ] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5 -> 4 -> 3
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5 -> 4 -> 3 -> 1
[ End ] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5 -> 4 -> 3 -> 1
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5 -> 4 -> 3 -> 2
[ End ] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5 -> 4 -> 3 -> 2
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5 -> 4 -> 3 -> 2 -> 0
[ End ] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5 -> 4 -> 3 -> 2 -> 0
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5 -> 4 -> 3 -> 2 -> 1
[ End ] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool-1-worker-1,5,main] path: 5 -> 4 -> 3 -> 2 -> 1
result: 5
單純的recursive堆疊概念
single thread[ForkJoinPool-1-worker-1,5,main]
有序列執行task的compute方法
不管執行幾次結果順序都會是一樣的
沒有平行處理的能力
Main Thread
利用main thread來執行task
Main寫法參考如下
Integer result = new Fibonacci(5, "5").compute();
Fibonacci範例同以上第一個例子f2.compute() + f1.join()
輸出結果如下(每次結果可能都不同)
poolSize: 4
[Start] inPool: false queuedTaskCount: 0 thread: Thread[main,5,main] path: 5
[ End ] inPool: false queuedTaskCount: 0 thread: Thread[main,5,main] path: 5
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool.commonPool-worker-1,5,main] path: 5 -> 4
[Start] inPool: false queuedTaskCount: 0 thread: Thread[main,5,main] path: 5 -> 3
[ End ] inPool: true queuedTaskCount: 1 thread: Thread[ForkJoinPool.commonPool-worker-1,5,main] path: 5 -> 4
[Start] inPool: true queuedTaskCount: 1 thread: Thread[ForkJoinPool.commonPool-worker-1,5,main] path: 5 -> 4 -> 2
[ End ] inPool: true queuedTaskCount: 2 thread: Thread[ForkJoinPool.commonPool-worker-1,5,main] path: 5 -> 4 -> 2
[Start] inPool: true queuedTaskCount: 1 thread: Thread[ForkJoinPool.commonPool-worker-1,5,main] path: 5 -> 4 -> 2 -> 0
[ End ] inPool: true queuedTaskCount: 1 thread: Thread[ForkJoinPool.commonPool-worker-1,5,main] path: 5 -> 4 -> 2 -> 0
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool.commonPool-worker-2,5,main] path: 5 -> 4 -> 3
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool.commonPool-worker-1,5,main] path: 5 -> 4 -> 2 -> 1
[ End ] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool.commonPool-worker-1,5,main] path: 5 -> 4 -> 2 -> 1
[ End ] inPool: true queuedTaskCount: 1 thread: Thread[ForkJoinPool.commonPool-worker-2,5,main] path: 5 -> 4 -> 3
[Start] inPool: true queuedTaskCount: 1 thread: Thread[ForkJoinPool.commonPool-worker-2,5,main] path: 5 -> 4 -> 3 -> 1
[ End ] inPool: true queuedTaskCount: 1 thread: Thread[ForkJoinPool.commonPool-worker-2,5,main] path: 5 -> 4 -> 3 -> 1
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool.commonPool-worker-2,5,main] path: 5 -> 4 -> 3 -> 2
[ End ] inPool: true queuedTaskCount: 1 thread: Thread[ForkJoinPool.commonPool-worker-2,5,main] path: 5 -> 4 -> 3 -> 2
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool.commonPool-worker-2,5,main] path: 5 -> 4 -> 3 -> 2 -> 0
[ End ] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool.commonPool-worker-2,5,main] path: 5 -> 4 -> 3 -> 2 -> 0
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool.commonPool-worker-1,5,main] path: 5 -> 4 -> 3 -> 2 -> 1
[ End ] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool.commonPool-worker-1,5,main] path: 5 -> 4 -> 3 -> 2 -> 1
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool.commonPool-worker-3,5,main] path: 5 -> 3 -> 2
[ End ] inPool: false queuedTaskCount: 0 thread: Thread[main,5,main] path: 5 -> 3
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool.commonPool-worker-2,5,main] path: 5 -> 3 -> 2 -> 1
[ End ] inPool: true queuedTaskCount: 1 thread: Thread[ForkJoinPool.commonPool-worker-3,5,main] path: 5 -> 3 -> 2
[ End ] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool.commonPool-worker-2,5,main] path: 5 -> 3 -> 2 -> 1
[Start] inPool: false queuedTaskCount: 0 thread: Thread[main,5,main] path: 5 -> 3 -> 1
[ End ] inPool: false queuedTaskCount: 0 thread: Thread[main,5,main] path: 5 -> 3 -> 1
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool.commonPool-worker-3,5,main] path: 5 -> 3 -> 2 -> 0
[ End ] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool.commonPool-worker-3,5,main] path: 5 -> 3 -> 2 -> 0
result: 5
每次結果雖然可能都不同
但是main thread一定會執行task(path: 5)
而且main thread不在pool中所以inPool為false
[Start] inPool: false queuedTaskCount: 0 thread: Thread[main,5,main] path: 5
f1 = new Fibonacci(4, ...)並且使用main thread來執行fork方法
因為不是使用ForkJoinWorkerThread緣故
所以f1放入ForkJoinPool.common.externalPush(this);
f2 = new Fibonacci(3, ...)
[ End ] inPool: false queuedTaskCount: 0 thread: Thread[main,5,main] path: 5
剛剛提到的f1在join時會使用ForkJoinWorkerThread來執行task(path: 5 -> 4)的compute方法
[Start] inPool: true queuedTaskCount: 0 thread: Thread[ForkJoinPool.commonPool-worker-1,5,main] path: 5 -> 4
由[ForkJoinPool.commonPool-worker-1,5,main]
來執行compute方法直到完成可以join為止
而f2則繼續由main thread來執行task(path: 5 -> 3)的compute方法
[Start] inPool: false queuedTaskCount: 0 thread: Thread[main,5,main] path: 5 -> 3
其餘請同上類推...
ref.
ForkJoinPool Example (Java Concurrency - Part 2)
ForkJoinPoolとForkJoinTaskの使い方とブロッキングの実装方法
聊聊并发(八)——Fork/Join框架介绍