completableFuture.allOf()用于多任务共同返回,配合get()使用来实现任务的等待。get()方法内部是waittingGet(),其是while()循环判断返回结果为null的话,则一直等待,如果线程不为null、返回结果为null,则线程阻塞等待。其源码如下:
public T get() throws InterruptedException, ExecutionException {
Object r;
/*
分为两种,线程执行比较快或者慢。执行比较慢的就进入 waitingGet(true)方法进行阻塞。
快的就直接返回结果信息
*/
return reportGet((r = result) == null ? waitingGet(true) : r);
}
//这个返回主要判断这个result是什么类型进行相关处理
private static <T> T reportGet(Object r)
throws InterruptedException, ExecutionException {
if (r == null) // by convention below, null means interrupted
throw new InterruptedException();
if (r instanceof AltResult) {
Throwable x, cause;
if ((x = ((AltResult)r).ex) == null)
return null;
if (x instanceof CancellationException)
throw (CancellationException)x;
if ((x instanceof CompletionException) &&
(cause = x.getCause()) != null)
x = cause;
throw new ExecutionException(x);
}
@SuppressWarnings("unchecked") T t = (T) r;
return t;
}
private Object waitingGet(boolean interruptible) {
Signaller q = null;
boolean queued = false;
int spins = -1;
Object r;
while ((r = result) == null) {
if (spins < 0)
//获取当前处理数量是否大于1,大于1 spins = 256 否则 0
spins = (Runtime.getRuntime().availableProcessors() > 1) ?
1 << 8 : 0; // Use brief spin-wait on multiprocessors
else if (spins > 0) {
//获取一个随机的数值,如果每次都大于等于0,--spins 到小于0为止
if (ThreadLocalRandom.nextSecondarySeed() >= 0)
--spins;
}
else if (q == null)
/**
注意,这个对象很关键。以下用q表示
Signaller(boolean interruptible, long nanos, long deadline) {
this.thread = Thread.currentThread();
this.interruptControl = interruptible ? 1 : 0;
this.nanos = nanos;
this.deadline = deadline;
}
*/
q = new Signaller(interruptible, 0L, 0L);
else if (!queued)
/**
stack next
原 this A B
q A
现 this q B
*/
queued = tryPushStack(q);
else if (interruptible && q.interruptControl < 0) {
q.thread = null;
cleanStack();
return null;
}
else if (q.thread != null && result == null) {
try {
// 假设线程不为空,并且没有返回结果。就是线程执行慢要进行阻塞了
ForkJoinPool.managedBlock(q);
} catch (InterruptedException ie) {
q.interruptControl = -1;
}
}
}
if (q != null) {
q.thread = null;
if (q.interruptControl < 0) {
if (interruptible)
r = null; // report interruption
else
Thread.currentThread().interrupt();
}
}
postComplete();
return r;
}
public static void managedBlock(ManagedBlocker blocker)
throws InterruptedException {
ForkJoinPool p;
ForkJoinWorkerThread wt;
Thread t = Thread.currentThread();
//当前测试线程是Main,直接分析else
if ((t instanceof ForkJoinWorkerThread) &&
(p = (wt = (ForkJoinWorkerThread)t).pool) != null) {
}
else {
//当前blocker就是上面传参q,直接分析q类型里面的这些方法
do {} while (!blocker.isReleasable() &&
!blocker.block());
}
}
public boolean block() {
//false
if (isReleasable())
return true;
//构造赋值时为0.
else if (deadline == 0L)
/**
this对象就是 q,阻塞的就是当前线程。
到这就找到了如何阻塞线程,那么他是如何定位该线程并唤醒的呢?
*/
LockSupport.park(this);
else if (nanos > 0L)
LockSupport.parkNanos(this, nanos);
return isReleasable();
}
public boolean isReleasable() {
if (thread == null)
return true;
//是否被中断
if (Thread.interrupted()) {
int i = interruptControl;
interruptControl = -1;
if (i > 0)
return true;
}
//构造时,有赋值。已当前分析,不进入
if (deadline != 0L &&
(nanos <= 0L || (nanos = deadline - System.nanoTime()) <= 0L)) {
thread = null;
return true;
}
return false;
}