JAVA Future类详解及Thread线程是如何运行Future类的
一、Future基本介绍
Future(java.util.concurrent Interface Future<V>)表示异步计算的结果。Future接口提供了检查计算是否完成、检查计算是否被取消、等待计算完成并获取计算结果等方法。
在并发编程中,我们经常用到非阻塞的模型,但继承thread类和实现runnable接口,都无法保证获取到之前的执行结果。而通过实现Callback接口,并用Future可以来接收多线程的执行结果。
Future表示一个可能还没有完成的异步任务的结果,针对这个结果可以添加Callback以便在任务执行成功或失败后作出相应的操作。
二、Future使用方法
public static void main(String[] args) throws ExecutionException, InterruptedException {
Callable call = new Callable<String>(){
@Override
public String call() throws Exception {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "我被调用";
}
};
FutureTask<String> future = new FutureTask<String>(call);
new Thread(future).start();
System.out.println(future.get());
}
返回结果“我被调用”
接下来我们就围绕这这段代码看看整体的运行流程。
我们这里主要关注的类是Callable 和FutureTask两个类
三、Callable类
Callable是个支持泛型的函数式接口,里面有个call()方法
四、FutureTask继承体系
RunnableFuture是个组合接口,继承了Future和Runnable两个接口,FutureTask实现了RunnableFuture接口,所以FutureTask拥有Future和Runnable两个接口的功能,我们知道Runnable接口是个函数式接口,里面只有一个run方法,我们重点看下Future这个类。
五、Future类接口说明
/**
* 方法可以用来停止一个任务,如果任务可以停止(通过mayInterruptIfRunning来进行判断),则可以返回true,
* 如果任务已经完成或者已经停止,或者这个任务无法停止,则会返回false
* 注意:mayInterruptIfRunning不一定会影响取消,要看具体实现,concurrent包里面部分类是不受该参数影响的,如CompletableFuture
*/
boolean cancel(boolean mayInterruptIfRunning);
/**
* 任务是否已经取消
*/
boolean isCancelled();
/**
* 任务是否已经完成
*/
boolean isDone();
/**
* 获取任务返回值,未执行完成则会阻塞等待结果
*/
V get() throws InterruptedException, ExecutionException;
/**
* 指定超时时间,规定时间未获取结果则抛出TimeoutException
*/
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
六、FutureTask的主要实现
我们知道我们调用了Thread的start()方法之后线程进入就绪状态,在线程获取运行资源之后会调用run()方法,所以我们就从这里入手,看看FutureTask的run()方法:
public void run() {
if (state != NEW ||
!RUNNER.compareAndSet(this, null, Thread.currentThread()))
return;
try {
// 这里是初始化我们传入的callable对象
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
// 调用callable的call方法并获取返回结果
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);
}
}
由上面的代码我们可以看到run()方法在执行的时候调用了我们传入的Callable对象的call()方法,并在成功执行后获取返回结果并对返回结果做封装,接下来我们看看封装返回结果的set()方法:
protected void set(V v) {
if (STATE.compareAndSet(this, NEW, COMPLETING)) {
// 将返回结果传到outcome参数中
outcome = v;
STATE.setRelease(this, NORMAL); // final state
finishCompletion();
}
}
FutureTask将Callable的call()方法的运行的返回结果传到outcome参数中,至此这个调用过程也结束了,我们看看父类Future的get方法的实现是如何获取返回参数的:
public V get() throws InterruptedException, ExecutionException {
int s = state;
if (s <= COMPLETING)
// 这里阻塞等待结果,可以跟进去看看,里面有个for循环一直等待结果
s = awaitDone(false, 0L);
return report(s);
}
跟进去report()方法:
private V report(int s) throws ExecutionException {
Object x = outcome;
if (s == NORMAL)
// 返回outcome对象
return (V)x;
if (s >= CANCELLED)
throw new CancellationException();
throw new ExecutionException((Throwable)x);
}
至此,我们就跟完了整个调用流程了。