1. 程式人生 > 其它 >Fork/Join 執行緒池

Fork/Join 執行緒池

簡述

  Fork/Join 是 JDK 1.7 加入的新的執行緒池實現,它體現的是一種分治思想,適用於能夠進行任務拆分的 cpu 密集型運算Fork/Join 在分治的基礎上加入了多執行緒,可以把每個任務的分解和合並交給不同的執行緒來完成,進一步提升了運算效率Fork/Join 預設會建立與 cpu 核心數大小相同的執行緒池

使用

  基本的使用流程就是建立任務然後交給執行緒池執行

  這裡的任務就不是runnable和callable的物件了,得用RecursiveTaskRecursiveAction的子類,前者有返回結果,後者沒有返回結果

  forkjoin執行緒池的分治思想和遞迴很類似,比如我們想要求1到n的和,若n=5時,

f(5) = 5 + f(4) f(4) = 4 + f(3)以此類推可以進行一個任務的拆分

  重寫的compute方法就是該遞迴方法

package ThreadTest.ThreadPool;

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;
import java.util.concurrent.RecursiveTask;

public class TestFork {
    public static void main(String[] args) {
        ForkJoinPool pool 
= new ForkJoinPool(5); System.out.println(pool.invoke(new MyTask(5))); //f(5) = 5 + f(4) f(4) = 4 + f(3)... } } class MyTask extends RecursiveTask<Integer> { private int n; public MyTask(int n) { this.n = n; } @Override protected Integer compute() {
if(n==1) return 1;//終止條件 MyTask t1 = new MyTask(n-1); t1.fork();//讓一個執行緒去執行 Integer result = n + t1.join();//獲取任務結果 return result; } }
sample

  任務拆分的優化,本來我們的任務拆分是這樣的:

  可以看到執行緒的並行度很低,執行緒都要依賴下一個拆分任務的執行緒的結束才能返回

  我們可以改變任務拆分的方式:

class AddTask1 extends RecursiveTask<Integer> {
    int n;
    public AddTask1(int n) {
        this.n = n;
    }
    @Override
    public String toString() {
        return "{" + n + '}';
    }
    @Override
    protected Integer compute() {
        // 如果 n 已經為 1,可以求得結果了
        if (n == 1) {
            log.debug("join() {}", n);
            return n;
        }

        // 將任務進行拆分(fork)
        AddTask1 t1 = new AddTask1(n - 1);
        t1.fork();
        log.debug("fork() {} + {}", n, t1);

        // 合併(join)結果
        int result = n + t1.join();
        log.debug("join() {} + {} = {}", n, t1, result);
        return result;
    }
}
sample2

  這樣用二分的思想,從中間開始拆分,呼叫鏈就是這樣了:

  可以看到t3和t2是可以並行的,這樣就能提高cpu資源利用率

一點一點積累,一點一點蛻變!