引言
FutureTask是Java并发编程中常用的一种类,它实现了RunnableFuture接口,用于异步执行任务。FutureTask可以用来表示一个异步计算的结果,它允许用户在任务完成时获取结果,或者在任务执行过程中取消任务。本文将深入解析FutureTask的源码,揭示其背后的奥秘与实现技巧。
FutureTask简介
FutureTask是Java并发包java.util.concurrent中的一个类,它实现了RunnableFuture接口,该接口继承自Runnable和Future接口。RunnableFuture接口定义了两个方法:run()和get()。
- run():执行任务的具体逻辑。
- get():获取任务执行的结果。
FutureTask内部维护了一个状态,用于表示任务的执行状态,包括NEW、RUNNING、FINISHED和CANCELLED等。
FutureTask源码解析
1. 构造函数
FutureTask的构造函数接受一个Runnable类型的参数,用于执行任务。以下是FutureTask构造函数的源码:
public FutureTask(Runnable runnable, V result) {
this.state = -1; // 初始化状态为NEW
this.count = 0;
this.runnable = runnable;
this.result = result;
}
2. run()方法
run()方法是FutureTask的核心方法,用于执行任务。以下是run()方法的源码:
public void run() {
if (this.state != NEW ||
!U.compareAndSwapInt(this, STATE, NEW, RUNNING)) {
return;
}
try {
this.runnable.run();
set(result);
} catch (Throwable ex) {
setException(ex);
}
}
在run()方法中,首先检查任务的状态是否为NEW,如果不是,则直接返回。然后,使用compareAndSwapInt方法尝试将状态从NEW修改为RUNNING。如果修改成功,则执行任务;如果失败,则说明其他线程已经执行了任务,当前线程不再执行。
3. get()方法
get()方法是FutureTask提供的一个获取任务执行结果的方法。以下是get()方法的源码:
public V get() throws InterruptedException, ExecutionException {
int s = state;
if (s >= RUNNING)
return report(s);
else if (s == NEW)
waitDone();
throw new IllegalStateException();
}
private void waitDone() throws InterruptedException {
U.putObject(this, WAITERS, Thread.currentThread());
try {
for (;;) {
int s = state;
if (s >= RUNNING)
return;
if (U.compareAndSwapInt(this, STATE, s, s | WAITING))
LockSupport.park(this);
}
} finally {
U.putObject(this, WAITERS, null);
}
}
private V report(int s) throws ExecutionException {
Object x = result;
if (x == EXCEPTION_CAUGHT)
throw (ExecutionException) x;
if (x instanceof Error)
throw (Error) x;
return (V) x;
}
在get()方法中,首先检查任务的状态。如果状态大于等于RUNNING,则调用report()方法获取结果。如果状态为NEW,则调用waitDone()方法等待任务完成。
4. set()方法和setException()方法
set()方法和setException()方法用于设置FutureTask的结果。以下是这两个方法的源码:
public void set(V v) {
if (!U.compareAndSwapInt(this, STATE, RUNNING, FINISHED)) {
throw new IllegalStateException();
}
result = v;
U.putObject(this, THREAD, null);
U.putObject(this, WAITERS, null);
LockSupport.unparkAll(this);
}
public void setException(Throwable ex) {
if (!U.compareAndSwapInt(this, STATE, RUNNING, FINISHED)) {
throw new IllegalStateException();
}
result = EXCEPTION_CAUGHT;
U.putObject(this, THREAD, null);
U.putObject(this, WAITERS, null);
LockSupport.unparkAll(this);
}
在set()方法中,首先检查任务的状态。如果状态为RUNNING,则将状态修改为FINISHED,并将结果设置为v。在setException()方法中,将结果设置为EXCEPTION_CAUGHT,表示任务执行过程中发生了异常。
实现技巧
使用compareAndSwapInt方法实现状态转换:FutureTask使用compareAndSwapInt方法实现状态转换,该方法是一个原子操作,可以保证状态转换的原子性。
使用LockSupport.park()和LockSupport.unpark()实现线程阻塞和唤醒:FutureTask使用LockSupport.park()方法使线程阻塞,使用LockSupport.unpark()方法唤醒线程。
使用volatile关键字保证共享变量的可见性:FutureTask中的共享变量result使用volatile关键字修饰,保证其可见性。
总结
FutureTask是Java并发编程中常用的一种类,它实现了RunnableFuture接口,用于异步执行任务。本文深入解析了FutureTask的源码,揭示了其背后的奥秘与实现技巧。通过理解FutureTask的源码,可以帮助我们更好地使用它,提高程序的性能和可靠性。
