Java8 ForkJoinPool(二) 源码解析

本文详细解析了Java8的ForkJoinPool,包括其定义、构造方法、任务提交(invoke/execute/submit/invokeAll)、externalPush/tryExternalUnpush方法以及lockRunState/unlockRunState的加锁解锁机制。ForkJoinPool通过多任务队列减少并发竞争,使用特定策略分配任务,并能灵活调整线程创建。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

        1、定义

2、构造方法

3、invoke / execute / submit / invokeAll

4、externalPush / tryExternalUnpush

5、lockRunState / unlockRunState


       本篇博客重点讲解ForkJoinPool的定义及其提交任务到线程池的实现。

1、定义

     ForkJoinPool的类继承关系如下:

   

该类包含的属性如下:

   //最高的16位表示获取线程数,第二个16位表示总的线程数
   //如果有空闲线程,最低的16位中保存空闲线程关联的WorkQueue在WorkQueue数组中的索引 
   volatile long ctl;                   // main pool control
    
    //描述线程池的状态
    volatile int runState;               // lockable status
    
    //高16位保存线程池的队列模式,FIFO或者LIFO
    //低16位保存线程池的parallelism属性
    final int config;                    // parallelism, mode
    
    //累加SEED_INCREMENT生成的一个随机数,决定新增的Worker对应的WorkQueue在数组中的索引
    int indexSeed;                       // to generate worker index

    //WorkQueue数组
    volatile WorkQueue[] workQueues;     // main registry
    
    //生成Worker线程的工厂类
    final ForkJoinWorkerThreadFactory factory;
    
    //异常处理器
    final UncaughtExceptionHandler ueh;  // per-worker UEH
    
    //生成的Worker线程的线程名前缀
    final String workerNamePrefix;       // to create worker name string
    
    //累计的从其他WorkQueue中偷过来的待执行的任务
    volatile AtomicLong stealCounter;    // also used as sync monitor

 包含的静态属性如下:

    //创建ForkJoinWorkerThread的工厂类
    public static final ForkJoinWorkerThreadFactory
        defaultForkJoinWorkerThreadFactory;

    //线程池关闭时检查当前线程是否有此权限
    private static final RuntimePermission modifyThreadPermission;

    //common线程池
    static final ForkJoinPool common;

    //common线程池的parallelism属性
    static final int commonParallelism;

    //限制最大的线程数,默认值为常量DEFAULT_COMMON_MAX_SPARES,256
    private static int commonMaxSpares;
   
    //生成poolId使用
    private static int poolNumberSequence;

    // Unsafe mechanics
    private static final sun.misc.Unsafe U;
    private static final int  ABASE;
    private static final int  ASHIFT;
    private static final long CTL;
    private static final long RUNSTATE;
    private static final long STEALCOUNTER;
    private static final long PARKBLOCKER;
    private static final long QTOP;
    private static final long QLOCK;
    private static final long QSCANSTATE;
    private static final long QPARKER;
    private static final long QCURRENTSTEAL;
    private static final long QCURRENTJOIN;

    static {
        //获取属性的偏移量
        try {
            U = sun.misc.Unsafe.getUnsafe();
            Class<?> k = ForkJoinPool.class;
            CTL = U.objectFieldOffset
                (k.getDeclaredField("ctl"));
            RUNSTATE = U.objectFieldOffset
                (k.getDeclaredField("runState"));
            STEALCOUNTER = U.objectFieldOffset
                (k.getDeclaredField("stealCounter"));
            Class<?> tk = Thread.class;
            PARKBLOCKER = U.objectFieldOffset
                (tk.getDeclaredField("parkBlocker"));
            Class<?> wk = WorkQueue.class;
            QTOP = U.objectFieldOffset
                (wk.getDeclaredField("top"));
            QLOCK = U.objectFieldOffset
                (wk.getDeclaredField("qlock"));
            QSCANSTATE = U.objectFieldOffset
                (wk.getDeclaredField("scanState"));
            QPARKER = U.objectFieldOffset
                (wk.getDeclaredField("parker"));
            QCURRENTSTEAL = U.objectFieldOffset
                (wk.getDeclaredField("currentSteal"));
            QCURRENTJOIN = U.objectFieldOffset
                (wk.getDeclaredField("currentJoin"));
            Class<?> ak = ForkJoinTask[].class;
            //用于获取ForkJoinTask数组指定索引元素的偏移量
            ABASE = U.arrayBaseOffset(ak);
            int scale = U.arrayIndexScale(ak);
            if ((scale & (scale - 1)) != 0)
                throw new Error("data type scale not a power of two");
            ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
        } catch (Exception e) {
            throw new Error(e);
        }
        
        //DEFAULT_COMMON_MAX_SPARES的值是256
        commonMaxSpares = DEFAULT_COMMON_MAX_SPARES;
        defaultForkJoinWorkerThreadFactory =
            new DefaultForkJoinWorkerThreadFactory();
        modifyThreadPermission = new RuntimePermission("modifyThread");

        common = java.security.AccessController.doPrivileged
            (new java.security.PrivilegedAction<ForkJoinPool>() {
                public ForkJoinPool run() { return makeCommonPool(); }});
        //获取common线程池的parallelism属性        
        int par = common.config & SMASK; // report 1 even if threads disabled
        commonParallelism = par > 0 ? par : 1;
    }

    //创建common线程池
    private static ForkJoinPool makeCommonPool() {
        int parallelism = -1;
        ForkJoinWorkerThreadFactory factory = null;
        UncaughtExceptionHandler handler = null;
        try {  //读取三个属性值
            String pp = System.getProperty
                ("java.util.concurrent.ForkJoinPool.common.parallelism");
            String fp = System.getProperty
                ("java.util.concurrent.ForkJoinPool.common.threadFactory");
            String hp = System.getProperty
                ("java.util.concurrent.ForkJoinPool.common.exceptionHandler");
            //根据属性配置初始化变量   
            if (pp != null)
                parallelism = Integer.parseInt(pp);
            if (fp != null)
                factory = ((ForkJoinWorkerThreadFactory)ClassLoader.
                           getSystemClassLoader().loadClass(fp).newInstance());
            if (hp != null)
                handler = ((UncaughtExceptionHandler)ClassLoader.
                           getSystemClassLoader().loadClass(hp).newInstance());
        } catch (Exception ignore) {
        }
        if (factory == null) {
            if (System.getSecurityManager() == null)
                factory = defaultForkJoinWorkerThreadFactory;
            else // use security-managed default
                factory = new InnocuousForkJoinWorkerThreadFactory();
        }
        if (parallelism < 0 && //如果没有设置属性parallelism,则默认使用CPU核数减1,如果是单核的则为1
            (parallelism = Runtime.getRuntime().availableProcessors() - 1) <= 0)
            parallelism = 1;
        if (parallelism > MAX_CAP) //如果配置的parallelism大于MAX_CAP,则为MAX_CAP,0x7fff,32767
            parallelism = MAX_CAP;
         //注意common线程池的模式是LIFO,后进先出    
        return new ForkJoinPool(parallelism, factory, handler, LIFO_QUEUE,
                                "ForkJoinPool.commonPool-worker-");
    }

 包含的静态常量如下:

    //用于获取保存在config属性低16位中的parallelism属性
    static final int SMASK        = 0xffff;        // short bits == max index
    //parallelism属性的最大值
    static final int MAX_CAP      = 0x7fff;        // max #workers - 1
    //跟SMASK相比,最后一
### ForkJoinPool 源码解析 #### 三者关系与框架结构 ForkJoinPool作为线程池,`ForkJoinTask`为任务,而`ForkJoinWorkerThread`则担当起执行这些任务的角色。这三种组件共同构建了一个高效的任务调度机制,在Java中被统称为ForkJoin框架[^3]。 #### 主要组成部分及其职责划分 - **ForkJoinPool**: 负责管理一组工作窃取线程以及它们共享的工作队列。它实现了对提交给它的各种形式的任务(通常是RecursiveAction或RecursiveTask类型的实例)的有效分配。 - **ForkJoinTask<T>**: 表示可能并行运行的操作;它是不可取消的轻量级异步计算单元。此类提供了用于启动、等待完成和获取结果的方法。子类需重写compute()方法来定义具体的行为逻辑[^4]。 - **ForkJoinWorkerThread**: 这种特殊的线程专门用来处理由ForkJoinPool所提交的任务。每个这样的线程都拥有自己的双端队列(deque),用于存储待处理的小型任务片段,并支持一种叫做“工作窃取”的策略——当某个线程完成了自己deque里的所有任务之后就会尝试从其他忙碌着的线程那里偷走一些未完成的任务来进行处理[^1]。 #### 关键特性之一:Invoke vs Fork+Join 值得注意的是,相比于传统的仅依赖于fork和join的方式,使用invoke可以让发起调用的那个线程也参与到实际的数据处理工作中去,从而提高了资源利用率,减少了不必要的上下文切换开销[^5]。 ```java // 使用 invoke 方法的例子 public class MyRecursiveTask extends RecursiveTask<Integer> { @Override protected Integer compute() { // 当满足条件时直接返回结果 if (/* some condition */) { return /* result */; } else { // 否则分割成更小的部分继续递归求解 MyRecursiveTask subtask = new MyRecursiveTask(/* parameters */); subtask.fork(); // 将子任务放入另一个可用的工作线程上并发执行 int currentResult = this.computeDirectly(); return currentResult + subtask.join(); // 获取子任务的结果并与当前部分相加得到最终答案 } } private int computeDirectly(){ // 实现具体的业务逻辑... return 0; } } ``` 为了更好地理解和掌握ForkJoinPool的具体运作方式,建议读者深入了解位运算的基础知识以及Java中的Unsafe类的相关概念,因为这些都是阅读源代码过程中不可或缺的知识点[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值