LoginSignup
0
0

More than 5 years have passed since last update.

[Java] Fork/Join compute vs join

Last updated at Posted at 2016-05-22

以Fibonacci series為例探討Fork/Join的compute和join
DSC_0788[1].JPG

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框架介绍

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0