1、 Future定义
Future是java1.5版本引进的一个接口,可以用来获取异步执行的结果,提供了一些查看异步任务状态的方法。
FutureTask是Future接口的一个实现类,常用来配合Callable任务,实现异步执行并能获取到任务的执行结果。
PS: 注意future接口获取异步任务返回的get方法是一个阻塞方法,要对其合理的使用。
- FutureTask关系图
- Future定义的一些方法
1、boolean cancel(boolean mayInterruptIfRunning)
尝试取消当前任务的执行。如果任务已经取消、已经完成或者其他原因不能取消,尝试将失败。如果任务还没有启动就调用了cancel(true),任务将永远不会被执行。如果任务已经启动,参数mayInterruptIfRunning将决定任务是否应该中断执行该任务的线程,以尝试中断该任务。
如果任务不能被取消,通常是因为它已经正常完成,此时返回false,否则返回true
2、boolean isCancelled()
查询任务是否取消成功
3、boolean isDone()
查询任务是否已经完成
4、V get() 阻塞方法
等待任务结束,然后获取结果,如果任务在等待过程中被终端将抛出InterruptedException,如果任务被取消将抛出CancellationException,如果任务中执行过程中发生异常将抛出ExecutionException。
5、V get(long timeout, TimeUnit unit)
任务最多在给定时间内完成并返回结果,如果没有在给定时间内完成任务将抛出TimeoutException。
- Future的简单例子
public static void main(String[] args) throws ExecutionException, InterruptedException {
Long startTime = System.currentTimeMillis();
FutureTask<String> futureTask1 = new FutureTask<>(new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(5000);
return "future1";
}
});
new Thread(futureTask1).start();
FutureTask<String> futureTask2 = new FutureTask<>(new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(3000);
return "future2";
}
});
new Thread(futureTask2).start();
//等待future1和future2执行完 ,get()阻塞
System.out.println(futureTask1.get() + "执行完!");
System.out.println(futureTask2.get() + "执行完!");
Long endTime = System.currentTimeMillis();
// 5004 可以看出future1和future2是异步执行的
System.out.println("共用时: " + (endTime - startTime));
}
2、FutureTask的源码解析
从上述例子,我们可以看到,FutureTask任务执行的调用是 new Thread(futureTask).start()
这样的,即线程将FutureTask当成一个Runnable任务体执行。
注:FutureTask本身就实现了RunnalbeFuture接口(即Runnable接口和Future接口)
可以着重看下FutureTask中的run()方法
public void run() {
// java不能直接访问操作系统底层,而是通过本地方法来访问,Unsafe类提供了硬件级别的原子操作。
// UNSAFE.compareAndSwapObject在obj的offset位置比较object field和期望的值,如果相同则更新。field值修改会返回true
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(); // 这里保存了Callable任务的返回值
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex); // 设置异常
}
if (ran)
set(result); // 设置任务执行结果
}
} finally {
runner = null;
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
set(result)方法:
protected void set(V v) {
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
outcome = v; //保存任务的返回结果,FutureTask的内部属性outcome
UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
finishCompletion();
}
}
可以看出,FutureTask只是将自己的run方法中实现对Callabe任务的执行和保存结果。
获取任务的返回值 FutureTask.get()方法
public V get() throws InterruptedException, ExecutionException {
int s = state;
if (s <= COMPLETING)
// 等待任务完成,并且移除waiters这个等待线程的节点
s = awaitDone(false, 0L);
return report(s); // 对返回值的封装,s其实是当前FutureTask的状态
}
可以看出FutureTask.get()是一个阻塞方法,在FutureTask中,state(当前任务运行状态)是用来判断任务是否完成的关键,
3、扩展
3.1、其实在set(result)方法中,UNSAFE方法操作state的地址状态为COMPLETING -> NORMAL,state也是FutureTask中其他方法判断是否执行的一个关键属性。
state的几种流转情况:
NEW -> COMPLETING -> NORMAL 正常情况
NEW -> COMPLETING -> EXCEPTIONAL 异常情况
NEW -> CANCELLED 被取消
NEW -> INTERRUPTING -> INTERRUPTED 被打断