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来实现的;

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