目录
5、complete / quietlyComplete/ completeExceptionally
6、recordExceptionalCompletion / clearExceptionalCompletion / getException
本篇博客讲解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)