Java 線程池源碼詳解(2)-ForkJoinPool 源碼解析 -- TBD

前言

ForkJoinPool作爲線程池,ForkJoinTask爲任務,ForkJoinWorkerThread作爲執行任務的線程,三者構成的任務調度機制在 Java 中通常被稱爲Fork/Join 框架

ForkJoin框架在 Java 7 的時候就加入到了 Java 併發包 java.util.concurrent,並且在 Java 8 的 lambda 並行流 中充當着底層框架的角色。其主要實現的功能是採用“分而治之”的算法將一個大型複雜任務 fork()分解成足夠小的任務才使用多線程去並行處理這些小任務,處理完得到各個小任務的執行結果後再進行join()合併,將其彙集成一個大任務的結果,最終得到最初提交的那個大型複雜任務的執行結果

ForkJoin框架最適合的是計算密集型的任務,如果存在 I/O,線程間同步,sleep() 等會造成線程長時間阻塞的情況時會影響整體效率,此時可配合使用 ManagedBlockerForkJoinPool 線程池爲了提高任務的並行度和吞吐量做了很多複雜的設計實現,目的是充分利用CPU,其中最著名的就是 work stealing任務竊取機制

  • ManagedBlocker 相當於明確告訴 ForkJoinPool 有個任務要阻塞了,ForkJoinPool 就會啓用另一個線程來運行任務,以最大化地利用CPU

在這裏插入圖片描述

1. ForkJoinPool 的組件

1.1 線程池 ForkJoinPool

ForkJoinPool 的繼承體系如下,可以看到它和 ThreadPoolExecutor 一樣都是繼承自AbstractExecutorService抽象類,所以它和 ThreadPoolExecutor 的使用幾乎沒什麼區別,只是任務對象變成了 ForkJoinTask
在這裏插入圖片描述

1.1.1 ForkJoinPool 線程池的創建

與其他線程池類似,ForkJoinPool 線程池可使用以下方式創建

  • Executors.newWorkStealingPool()
    public static ExecutorService newWorkStealingPool(int parallelism) {
         return new ForkJoinPool
             (parallelism,
              ForkJoinPool.defaultForkJoinWorkerThreadFactory,
              null, true);
     }
    

構造方法中各個參數的含義如下:

  1. parallelism: 並行度
    即配置線程池線程個數,如果沒有指定,則默認爲Runtime.getRuntime().availableProcessors() - 1,最大值不能超過 MAX_CAP =32767,可通過以下方式自定義配置
    System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "8");
    // 或者啓動參數指定
    -Djava.util.concurrent.ForkJoinPool.common.parallelism=8
    
  2. factory: 工作線程創建工廠
  3. handler: 未捕獲異常的處理器類
    多線程中子線程拋出的異常是無法被主線程 catch 的,因此需要使用 UncaughtExceptionHandler 對異常進行統一處理
  4. asyncMode: 任務隊列出隊模式
    默認爲 false,使用 LIFO(後入先出,類似棧結構)策略處理任務;爲 true 時處理策略是 FIFO(先進先出),更接近於一個消息隊列,不適用於處理遞歸式的任務
1.1.2 ForkJoinPool 線程池重要屬性
    // 配合ctl在控制線程數量時使用
    private static final long ADD_WORKER = 0x0001L << (TC_SHIFT + 15); 
  
    // 控制ForkJoinPool創建線程數量,(ctl & ADD_WORKER) != 0L 時創建線程,也就是當ctl的第16位不爲0時,可以繼續創建線程
    volatile long ctl;                   // main pool control
    // 全局鎖控制,全局運行狀態
    volatile int runState;               // lockable status
    // 低16位表示記錄並行數量,高16位表示 ForkJoinPool 處理任務的模式(異步/同步)
    final int config;                    // parallelism, mode
    // 工作任務隊列數組
    volatile WorkQueue[] workQueues;     // main registry
    // 默認線程工廠,默認實現是DefaultForkJoinWorkerThreadFactory
    final ForkJoinWorkerThreadFactory factory;

1.2 工作線程 ForkJoinWorkerThread

1.3 線程任務 ForkJoinTask

2. 任務執行流程

3. work stealing 算法

(1)每個工作線程都有自己的工作隊列WorkQueue;

(2)這是一個雙端隊列,它是線程私有的;

(3)ForkJoinTask中fork的子任務,將放入運行該任務的工作線程的隊頭,工作線程將以LIFO的順序來處理工作隊列中的任務;

(4)爲了最大化地利用CPU,空閒的線程將從其它線程的隊列中“竊取”任務來執行;

(5)從工作隊列的尾部竊取任務FIFO,以減少競爭;

(6)雙端隊列的操作:push()/pop()僅在其所有者工作線程中調用,poll()是由其它線程竊取任務時調用的;

(7)當只剩下最後一個任務時,還是會存在競爭,是通過CAS來實現的;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章