这是我参与8月更文挑战的第31天,活动详情查看:8月更文挑战
一般来说,Future我们是用于接收一个与异步任务返回的结果的。
Future接口的方法如下:
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
如果是使用线程池,那么我们提交线程的过程一般会通过submit(runnable) 方法,这个方法在
AbstractExecutorService
类中,方法如下:
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
return new FutureTask<T>(runnable, value);
}
在这里我们会发现,实际上提交到线程池中,线程的运行和普通无结果的异步任务是相同的,那么区别就在这个
FutureTask中了。
我们来看看FutureTask的源码:
public class FutureTask<V> implements RunnableFuture<V> {
//...
}
//实际上这个接口只规定了一个run方法:
//public interface RunnableFuture<V> extends Runnable, Future<V> {
/**
* Sets this Future to the result of its computation
* unless it has been cancelled.
*/
//void run();
//}
查看一下内部的变量:
//这里可以看到,future也提供了一套和thread中类似的线程状态值
private volatile int state;
private static final int NEW = 0;
private static final int COMPLETING = 1;
private static final int NORMAL = 2;
private static final int EXCEPTIONAL = 3;
private static final int CANCELLED = 4;
private static final int INTERRUPTING = 5;
private static final int INTERRUPTED = 6;
//其实这个是我们提交的任务
private Callable<V> callable;
//这个就是我们的结果了,注释里写的也很有意思:这个变量的可见性是通过state值的volatile间接保证的
private Object outcome; // non-volatile, protected by state reads/writes
//下面两个后面再说
private volatile Thread runner;
private volatile WaitNode waiters;
回顾一下我们之前使用Future的方式:
- 任务提交到线程池,并获取future对象
- 调用future.get()
那么我们就分两步,来看一下future对应是如何工作的。
1.提交
提交到线程池就不再赘述了,简要提一下我们提交的时候调用的方法是构造方法:
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
然后根据上面线程池抽象类提供的信息,我们就直接将这个作为任务塞到线程池中去运行了,根据之前看线程池的经验,我们这时候看看这个的run方法:
public void run() {
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
set(result);
}
} finally {
// runner must be non-null until state is settled to
// prevent concurrent calls to run()
runner = null;
// state must be re-read after nulling runner to prevent
// leaked interrupts
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
这里能看到,实际上我们任务塞到线程池并执行完毕,其实是这样子的流程:
- 任务组装成futureTask
- futureTask被分派到线程池中等待执行
- 执行完毕,结果储存在futureTask对象中
2.获取
public V get() throws InterruptedException, ExecutionException {
int s = state;
if (s <= COMPLETING)
s = awaitDone(false, 0L);
return report(s);
}
private int awaitDone(boolean timed, long nanos)
throws InterruptedException {
final long deadline = timed ? System.nanoTime() + nanos : 0L;
WaitNode q = null;
boolean queued = false;
for (;;) {
if (Thread.interrupted()) {
removeWaiter(q);
throw new InterruptedException();
}
int s = state;
if (s > COMPLETING) {
if (q != null)
q.thread = null;
return s;
}
else if (s == COMPLETING) // cannot time out yet
Thread.yield();
else if (q == null)
q = new WaitNode();
else if (!queued)
queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
q.next = waiters, q);
else if (timed) {
nanos = deadline - System.nanoTime();
if (nanos <= 0L) {
removeWaiter(q);
return state;
}
LockSupport.parkNanos(this, nanos);
}
else
LockSupport.park(this);
}
}
private V report(int s) throws ExecutionException {
Object x = outcome;
if (s == NORMAL)
return (V)x;
if (s >= CANCELLED)
throw new CancellationException();
throw new ExecutionException((Throwable)x);
}
futureTask中的精华,一部分就在awaitDone里面了。
- 维护了一个等待队列(waitNode)并返回当前的处理状态
- 使用CAS来保证状态值的原子性。