一、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>(){@Overridepublic 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 interruptsint 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 statefinishCompletion();}
}
FutureTask将Callable的call()方法的运行的返回结果传到outcome参数中,至此这个调用过程也结束了,我们看看父类Future的get方法的实现是如何获取返回参数的:
public V get() throws InterruptedException, ExecutionException {int s = state;if (s <= COMPLETING)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);
}
至此,我们就跟完了整个调用流程了。