其中有错误和不足之处请大家提出来,希望和大家一起讨论学习和进步;首先来看官方对Future的描述:Future 表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果。
接下来看下Future框架类结构图(没有包含全部,当前先研究比较常用的FutureTask)
从图中可以看到FutureTask直接继承自RunableFuture,RunableFuture分别继承自Future和Runable;Runable大家都很熟悉,就是一个run方法并没有返回结果,只管执行;而Future中就是一些获取线程运行状态和结果的方法了;
接下来我们结合FutureTask源码来解析FutureTask的原理,从上面FutureTask的类图中可以看出,FutureTask就一个属性sync,这是一个复杂类型的属性,其类型是FutureTask的私有内部类Sync,获取线程运行状态和执行结果的核心逻辑就是在这个类中实现的;先看FutureTask这个实现类,他有两个含参构造函数
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
sync = new Sync(callable);
}
和
public FutureTask(Runnable runnable, V result) {
sync = new Sync(Executors.callable(runnable, result));
}
这两个构造函数区别在于,如果使用第一个构造函数最后获取线程实行结果就是
callable的执行的返回结果;而如果使用第二个构造函数那么最后获取线程实行结果就是参数中的
result,接下来让我们看一下FutureTask的run方法
public void run() {
sync.innerRun();
}
正如上面所提到的,实现是在
sync类中,那么我们就接着看
sync.innerRun()方法
void innerRun() {
if (!compareAndSetState(0, RUNNING))
return;
try {
runner = Thread.currentThread();
if (getState() == RUNNING) // recheck after setting thread
innerSet(callable.call());
else
releaseShared(0); // cancel
} catch (Throwable ex) {
innerSetException(ex);
}
}
在这里首先提一下FutureTask中所有的状态的改变和加锁、阻塞都是动过AQS数据结构来实现的就是AbstractQueuedSynchronizer,有兴趣的可了解下;
标识FutureTask线程的状态字段是AbstractQueuedSynchronizer.Node.state;方法innerRun首先判断线程是否是初始状态,如果是就将状态变成执行中状态,也就是compareAndSetState(0, RUNNING)做的事情;修改状态之后就是执行线程方法,并把结果赋值给Sync.result字段对应代码为 innerSet(callable.call());我们自己实现的线程逻辑也就是通过<span style="font-family: Arial, Helvetica, sans-serif;">callable.call()执行的,接下来</span><span style="font-family: Arial, Helvetica, sans-serif;">我们在看一下innerSet方法</span>
void innerSet(V v) {
for (;;) {
int s = getState();
if (s == RAN)
return;
if (s == CANCELLED) {
// aggressively release to set runner to null,
// in case we are racing with a cancel request
// that will try to interrupt runner
releaseShared(0);
return;
}
if (compareAndSetState(s, RAN)) {
result = v;
releaseShared(0);
done();
return;
}
}
}
这段方法的逻辑就是判断当前线程执行状态,如果正在执行就把转态改为执行完毕状态,并把执行结果赋值给Sync.result,若为终止状态,就直接返回;ok,接下来我再看看获取线程执行结果get方法
public V get() throws InterruptedException, ExecutionException {
return sync.innerGet();
}
同样的逻辑在sync.innerGet()中
V innerGet() throws InterruptedException, ExecutionException {
acquireSharedInterruptibly(0);
if (getState() == CANCELLED)
throw new CancellationException();
if (exception != null)
throw new ExecutionException(exception);
return result;
}
该方法会一直阻塞到线程执行完毕,线程执行中间如被取消获中断则抛出相应异常,其他几个方法也都类似;整个Future框架FutureTask的实现难点还是在于状态的改变和加锁、阻塞的过程也就是AbstractQueuedSynchronizer实现,接下来的一篇就着重介绍AbstractQueuedSynchronizer的原理,敬请期待