上一次分析了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