Java8 ForkJoinTask 源码解析

本文详细解析了Java8中的ForkJoinTask,包括其定义、fork、join、invoke等关键方法的实现细节和使用。ForkJoinTask是ForkJoinPool中用于并行计算的任务,通过这些方法可以实现高效的任务调度和执行。文章还通过实例展示了不同方法的行为,并探讨了可能遇到的阻塞和异常处理情况。
摘要由CSDN通过智能技术生成

目录

1、定义

2、fork 

3、join / quietlyJoin

4、invoke / quietlyInvoke

5、complete / quietlyComplete/ completeExceptionally

6、recordExceptionalCompletion / clearExceptionalCompletion / getException 

7、invokeAll

8、get

9、tryUnfork / reinitialize


      本篇博客讲解ForkJoinTask的fork,join,invoke等方法的实现细节及其使用。

1、定义

       ForkJoinTask表示在ForkJoinPool中执行的一个任务,其类继承关系如下:

该类是一个抽象类,有多个子类,如下:

带S的几个大都是ForkJoinTask的内部类,其实现比较简单,用于将Runnable等接口转换成ForkJoinTask类,对应于ForkJoinPool的adapt方法,以AdaptedCallable的实现为例说明,如下:

public static <T> ForkJoinTask<T> adapt(Callable<? extends T> callable) {
        return new AdaptedCallable<T>(callable);
    }

static final class AdaptedCallable<T> extends ForkJoinTask<T>
        implements RunnableFuture<T> {
        final Callable<? extends T> callable;
        T result;
        AdaptedCallable(Callable<? extends T> callable) {
            if (callable == null) throw new NullPointerException();
            this.callable = callable;
        }
        public final T getRawResult() { return result; }
        public final void setRawResult(T v) { result = v; }

        //改写核心的exec方法
        public final boolean exec() {
            try {
                result = callable.call();
                return true;
            } catch (Error err) {
                throw err;
            } catch (RuntimeException rex) {
                throw rex;
            } catch (Exception ex) {
                throw new RuntimeException(ex);
            }
        }
        public final void run() { invoke(); }
        private static final long serialVersionUID = 2838392045355241008L;
    }

该类包含的属性如下:

 //保存ExceptionNode的数组,单个数组元素对应一个ExceptionNode链表
 private static final ExceptionNode[] exceptionTable;

 //修改exceptionTable时的锁
 private static final ReentrantLock exceptionTableLock;
 
 //保存被清楚掉的弱引用的队列   
 private static final ReferenceQueue<Object> exceptionTableRefQueue;

 //任务的状态,初始值为0,大于等于0时表示任务未执行或者正在执行的过程中,小于0表示已执行完成
 volatile int status; // accessed directly by pool and workers

  静态属性通过static代码块初始化,如下:

  该类定义的常量如下:

    //最高位为1
    static final int DONE_MASK   = 0xf0000000;  // mask out non-completion bits
    
    //正常完成
    static final int NORMAL      = 0xf0000000;  // must be negative
    
    //任务被取消了
    static final int CANCELLED   = 0xc0000000;  // must be < NORMAL
    
    //任务异常终止
    static final int EXCEPTIONAL = 0x80000000;  // must be < CANCELLED
    
    //某个线程在等待当前任务执行完成,需要在任务结束时唤醒等待的线程
    static final int SIGNAL      = 0x00010000;  // must be >= 1 << 16
    
    //获取低16位的值
    static final int SMASK       = 0x0000ffff;  // short bits for tags

    private static final int EXCEPTION_MAP_CAPACITY = 32;

 其中ExceptionNode是一个继承自WeakReference的内部类,其定义如下:

 

多个ExceptionNode通过next属性构成一个链表。

2、fork 

      fork方法并不是如其方法名会fork一个新线程来执行任务,只是将任务提交到任务队列中而已,然后立即返回,不会等待任务执行完成,其实现如下:

//fork方法并不是如其命名会创建一个新线程来执行任务,只是将任务提交到任务队列中而已
public final ForkJoinTask<V> fork() {
        Thread t;
        if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread)
            //如果当前线程是ForkJoinWorkerThread,将其提交到关联的WorkQueue中
            ((ForkJoinWorkerThread)t).workQueue.push(this);
        else
            //如果是普通线程,则提交到common线程池的任务队列中
            ForkJoinPool.common.externalPush(this);
        return this;
    }

其测试用例如下: 

 @Test
    public void test() throws Exception {
        ForkJoinTask task=ForkJoinTask.adapt(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                    System.out.println(Thread.currentThread().getName()+" exit");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        //提交任务到common线程池
        task.fork();
        //阻塞等待任务执行完成,get方法会将该任务从任务队列中pop出来并执行
        //所以run方法打印出来的线程名就是main
        task.get();
        System.out.println("main thread exit");
    }

其输出如下:

可以在adapt方法对应的AdaptedRunnableAction打断点,如下:

然后debug,观察调用链如下:

3、join / quietlyJoin

     join方法用于阻塞当前线程,等待任务执行完成,部分情形下会通过当前线程执行任务,如果异常结束或者被取消需要抛出异常;quietlyJoin方法只是阻塞当前线程等待任务执行完成,不会抛出异常;其实现如下:

//join方法等待任务执行完成并返回结果,如果出现异常则报告异常
public final V join() {
        int s;
        //doJoin方法会阻塞当前线程直到任务执行完成并返回任务的状态
        if ((s = doJoin() & DONE_MASK) != NORMAL)
            //如果不是正常完成的,则报告异常
            reportException(s);
        //返回执行结果,该方法是抽象方法    
        return getRawResult();
    }

public final void quietlyJoin() {
        doJoin(); //只是等待任务执行完成
    }


private void reportException(int s) {
        if (s == CANCELLED)
            //被取消了
            throw new CancellationException();
        if (s == EXCEPTIONAL)
            //重新抛出异常
            rethrow(getThrowableException());
    }

static void rethrow(Throwable ex) {
        if (ex != null)
            ForkJoinTask.<RuntimeException>uncheckedThrow(ex);
    }

@SuppressWarnings("unchecked") static <T extends Throwable>
        void uncheckedThrow(Throwable t)
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值