Java源码分析

来源:互联网 发布:医学英文写作软件 编辑:程序博客网 时间:2024/06/09 16:38

前言

最近在处理多线程的问题上.频繁的听到Join/Fork这个名词,在学习多线程的时候也有介绍过,太久没有基本都忘记了.

首先介绍几篇关于Fork/Join的文章

1.Fork and Join: Java Can Excel at Painless Parallel Programming Too!

2.《Java 7并发编程实战手册》第五章Fork/Join框架

需要先了解一下Fork/Join的相关知识,再来读本文章.本文章主要分析ForkJoinTask类.使用版本是Java8.

多线程发展历程

Thread => Executor => Fork/Join

在我们进行普通多线程的操作时候,我们通常会使用Thread和Runnable去操作,

但是我们通常没有办法很好管理.

到Java1.5时候Executor诞生,有效的帮我们管理起这些线程的状态.

Java7时,就诞生了Fork/Join框架.框架的核心思想是将问题拆分成小任务,然后在将产生的结果合并.思想很类似于MapReduce,有兴趣可以去了解一下.

ForkJoinTask源码分析

本文章只解析几个关键的方法(常用的方法)以及他们所涉及的方法.

fork方法

fork方法是属于所有方法的基石,将我们的任务进行拆分.下面看一下源码.

//设计成fianl让子类无法去破坏.   public final ForkJoinTask<V> fork() {        Thread t;        //如果当前的线程是Fork/join的线程,就添加到队列中        if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread)            ((ForkJoinWorkerThread)t).workQueue.push(this);        else          //当task是直接被调用,而不是使用ForkJoinWorkerThread的话,直接执行任务.            ForkJoinPool.common.externalPush(this);        return this;    }

这里需要注意的是workqueue是ForkJoinPool的一个内部类对象.并且workQueue不是没有继承queue接口,具体实现有兴趣的可以了解一下,以后也许会分析一下.今天还是主要讲ForkJoinTask.

final ForkJoinPool.WorkQueue workQueue;

如果不是则执行任务.这个方法的解析放在ForkJoinPool进行讲解.

Join方法

执行子任务并合并子任务的结果集.下面详细介绍

 public final V join() {        int s;        //执行任务        if ((s = doJoin() & DONE_MASK) != NORMAL)            reportException(s);        return getRawResult();    } private int doJoin() {        int s; Thread t; ForkJoinWorkerThread wt; ForkJoinPool.WorkQueue w;        //判断执行的状态        return (s = status) < 0 ? s :            //判断是否fork/join的线程            ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ?             //判断是否在队列的头部 && 在执行头部            (w = (wt = (ForkJoinWorkerThread)t).workQueue).            tryUnpush(this) && (s = doExec()) < 0 ? s :            //加入到等待的队列            wt.pool.awaitJoin(w, this, 0L) :            //不是fork/join线程 阻塞            externalAwaitDone();    }

doJoin方法是进行合并,合并之前需要进行判断,看当前的任务是否可以执行,如果可以执行则调用doExec方法,如果不能执行则加入等待的队列.这里简单看一下awaitJoin方法

 final int awaitJoin(WorkQueue w, ForkJoinTask<?> task, long deadline) {        int s = 0;        if (task != null && w != null) {          //获取上一个task            ForkJoinTask<?> prevJoin = w.currentJoin;            U.putOrderedObject(w, QCURRENTJOIN, task);          //判断是否为CountedCompleter对象 是ForkJoinTask的一个子类,可以理解为一种拓展          CountedCompleter<?> cc = (task instanceof CountedCompleter) ?                (CountedCompleter<?>)task : null;            for (;;) {                if ((s = task.status) < 0)                    break;                if (cc != null)                    helpComplete(w, cc, 0);              //再次判断是否为顶部,尝试执行和移除task                else if (w.base == w.top || w.tryRemoveAndExec(task))                    helpStealer(w, task);              //再次判断                if ((s = task.status) < 0)                    break;                long ms, ns;                if (deadline == 0L)                    ms = 0L;                else if ((ns = deadline - System.nanoTime()) <= 0L)                    break;                else if ((ms = TimeUnit.NANOSECONDS.toMillis(ns)) <= 0L)                    ms = 1L;                if (tryCompensate(w)) {                    task.internalWait(ms);                    U.getAndAddLong(this, CTL, AC_UNIT);                }            }            U.putOrderedObject(w, QCURRENTJOIN, prevJoin);        }        return s;    }

在awaitJoin中会执行ryRemoveAndExec方法

final boolean tryRemoveAndExec(ForkJoinTask<?> task) {            ForkJoinTask<?>[] a; int m, s, b, n;            //判断是否为空            if ((a = array) != null && (m = a.length - 1) >= 0 &&                task != null) {                //遍历 找到task,尝试进行执行和删除操作                while ((n = (s = top) - (b = base)) > 0) {                    for (ForkJoinTask<?> t;;) {      // traverse from s to b                        long j = ((--s & m) << ASHIFT) + ABASE;                        if ((t = (ForkJoinTask<?>)U.getObject(a, j)) == null)                            return s + 1 == top;     // shorter than expected                        else if (t == task) {                            boolean removed = false;                            if (s + 1 == top) {      // pop                                if (U.compareAndSwapObject(a, j, task, null)) {                                    U.putOrderedInt(this, QTOP, s);                                    removed = true;                                }                            }                            else if (base == b)      // replace with proxy                              //移除                                removed = U.compareAndSwapObject(                                    a, j, task, new EmptyTask());                            if (removed)                              //执行task里面的任务                                task.doExec();                            break;                        }                        else if (t.status < 0 && s + 1 == top) {                            if (U.compareAndSwapObject(a, j, t, null))                                U.putOrderedInt(this, QTOP, s);                            break;                  // was cancelled                        }                        if (--n == 0)                            return false;                    }                    if (task.status < 0)                        return false;                }            }            return true;        }

我们主要的目的是引出 task.doExec()方法,其他的关于ForkJoinPool方法不做过多讲解.在分析ForkJoinPool类时再仔细讲解.

doExec方法主要代码如下

final int doExec() {        int s; boolean completed;        //判断状态,是否执行        if ((s = status) >= 0) {            try {              //执行                completed = exec();            } catch (Throwable rex) {                return setExceptionalCompletion(rex);            }          //完成任务,修改状态            if (completed)                s = setCompletion(NORMAL);        }        return s;    }//执行,最终还是调用我们子类复写的 compute()方法protected final boolean exec() {        compute();        return true; }

从这整个流程可以看出,ForkJoinTask最终是一个循环,我们在compute方法中不能再继续拆分的时候循环才会结束,和我们了解的拆分机制很吻合.然后我们在将结果一级一级的进行合并.最终结束任务.

我们在ForkJoinTask类中,只是了解了task的执行流程,为此我们还看不出工作窃取功能,我们需要在ForkJoinPool类中进行了解.

本文章还涉及到了Unsafe类的操作.本文章主要使用了Unsafe类中的原子操作的特性进行数据操作.关于详细内容大家可以自行去了解.

RecursiveAction&&RecursiveTask

RecursiveAction是ForkJoinTask的一个子类,通常用于不用返回结果的Task

RecursiveTask是ForkJoinTask的一个子类,通常用于有返回结果的Task

    //RecursiveAction的exec方法    protected final boolean exec() {  this.compute();  return true;}//RecursiveTask的exec方法 protected final boolean exec() {        result = compute();        return true;    }

结语

本文暂时就ForkJoinTask类的Fork方法和Join方法展开讲解,其他方法暂时没有用上,以后再对有需要的方法进行补充,

通过这两个方法我们了解到ForkJoinTask是如何对任务进行拆分和结果合并的。本人能力有限,如有什么不合理或者错误的地方,欢迎批评和指正。

原创粉丝点击