ForkJoin源码分析之Task

上一次分析了ForkJoinPool构造时做了哪些工作,现在看一下这个框架的task是怎么玩的。task有一个顶层设计的接口就是ForkJoinTask,有两个类继承了这个接口,分别是RecursiveTask,RecursiveAction。区别就是一个任务有返回值一个任务没有返回值。看看两个task的定义:

public abstract class RecursiveTask<V> extends ForkJoinTask<V> {
    private static final long serialVersionUID = 5232453952276485270L;

    /** * The result of the computation. */
    V result;

    /** * The main computation performed by this task. */
    protected abstract V compute();

    public final V getRawResult() {
        return result;
    }

    protected final void setRawResult(V value) {
        result = value;
    }

    /** * Implements execution conventions for RecursiveTask. */
    protected final boolean exec() {
        result = compute();
        return true;
    }

}

从这里看到RecursiveTask 是带返回值的。并且继承RecursiveTask 类时需要实现compute方法。

public abstract class RecursiveAction extends ForkJoinTask<Void> {
    private static final long serialVersionUID = 5232453952276485070L;

    /** * The main computation performed by this task. */
    protected abstract void compute();

    /** * Always returns {@code null}. * * @return {@code null} always */
    public final Void getRawResult() { return null; }

    /** * Requires null completion value. */
    protected final void setRawResult(Void mustBeNull) { }

    /** * Implements execution conventions for RecursiveActions. */
    protected final boolean exec() {
        compute();
        return true;
    }

}

RecursiveAction 这个类不能带返回值,因为在getRawResult方法中直接返回了null。同样,继承这个类实现的task也要实现compute方法才行。

这里用了一个模板方法的设计模式,这个设计模式的作用是定义好一个算法骨架,在不改变算法结构的情况下,将算法中特定的步骤实现推迟到子类中来处理。这里compute方法是个抽象方法,用于子类实现,但是exec方法确定final的,子类不能overwrite,框架可以调用exec方法来使得整个算法保持完整。

最后看看这个顶层设计ForkJoinTask。这个类也许有三点需要重点关注。
第一:在我们代码逻辑中调用的invokeAll(ForkJoinTask

public final ForkJoinTask<V> fork() {
        ((ForkJoinWorkerThread) Thread.currentThread())
            .pushTask(this);
        return this;
    }

这个方法调用到了ForkJoinWorkThread中的pushTask方法,ForkJoinWorkerThread对象其实已经初始化了….在pool 初始化的时候,继续看。

final void pushTask(ForkJoinTask<?> t) {
        ForkJoinTask<?>[] q; int s, m;
        if ((q = queue) != null) {    // ignore if queue removed
            long u = (((s = queueTop) & (m = q.length - 1)) << ASHIFT) + ABASE;
            UNSAFE.putOrderedObject(q, u, t);
            queueTop = s + 1;         // or use putOrderedInt
            if ((s -= queueBase) <= 2)
                pool.signalWork();
            else if (s == m)
                growQueue();
        }
    }

这里其实又调用到pool的signalWork()方法了。
这个方法很复杂,后续分析。

第三点看一下UNSAFE类的用法。这个类我们使用不了。主要是JDK来使用。这里有个文章可以参考,http://aswang.iteye.com/blog/1741871

你可能感兴趣的:(源码,框架)