Future
获取任务的执行结果,一般是搭配ExecutorService使用。
Future接口
image.png获取单个线程的执行结果
- 调用V Future.get()方法能够阻塞等待执行结果
- V get(long timeout, TimeUnit unit)方法可以指定等待的超时时间
// 取消任务
boolean cancel(boolean mayInterruptIfRunning);
// 获取任务执行结果
V get() throws InterruptedException, ExecutionException;
// 获取任务执行结果,带有超时时间限制
V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
// 判断任务是否已经取消
boolean isCancelled();
// 判断任务是否已经结束
boolean isDone();
FutureTask
使用场景:
- 阻塞:Future是对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果、设置结果操作,get方法会阻塞,直到任务返回结果,也就是说,阻塞。
- 在高并发环境下确保任务只执行一次(这个嗯。。。我觉得了解一下吧,感觉很牵强)
FutureTask类图
FutureTask类图从类图可以看出FutureTask即拥有Runnable特性又有Future特性。
FutureTask方法
FutureTask方法图AQS无非关注点在于:状态(业务主要逻辑控制)、队列(等待队列)、CAS(安全set值)
FutureTask构造函数
两个构造函数,入参分别是Runnable、Callable,我们知道Runnable没有返回值,这两个构造函数实际上都是转到Callable来实现返回值。
/**
* Creates a {@code FutureTask} that will, upon running, execute the
* given {@code Runnable}, and arrange that {@code get} will return the
* given result on successful completion.
*
* @param runnable the runnable task
* @param result the result to return on successful completion. If
* you don't need a particular result, consider using
* constructions of the form:
* {@code Future<?> f = new FutureTask<Void>(runnable, null)}
* @throws NullPointerException if the runnable is null
*/
public FutureTask(Runnable runnable, V result) {
this.callable = Executors.callable(runnable, result);
this.state = NEW; // ensure visibility of callable
}
/**
* Creates a {@code FutureTask} that will, upon running, execute the
* given {@code Callable}.
*
* @param callable the callable task
* @throws NullPointerException if the callable is null
*/
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
image.png
- Callable执行的方法是call(),Runnable执行的方法是run()。其中Runnable可以提交给Thread来包装下,直接启动一个线程来执行,或者交给ExecuteService执行,而Callable则一般都是提交给ExecuteService来执行。
- Callable的任务执行后可返回值,而Runnable的任务是不能返回值得
- call方法可以抛出异常,run方法不可以
- 运行Callable任务可以拿到一个Future对象,表示异步计算的结果,而且拿到的这个Future对象后,如果调用get()方法,当前线程会阻塞,直到此Callable的call方法执行完毕。
举例一(由Thread执行):
public static void main(String[] args) {
CountSum countSum = new CountSum();// 创建一个Callable对象
FutureTask<Integer> futureTask = new FutureTask<>(countSum);// 创建FutureTask对象
Thread thread = new Thread(futureTask);// 开启线程
thread.start();
try {
int sum = futureTask.get();
System.out.println("主线程获得求和结果:" + sum);
} catch (Exception e) {
e.printStackTrace();
futureTask.cancel(true);
}
}
static class CountSum implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println("开始求和");
int sum = 0;
for (int i = 0; i < 10000; i++) {
sum += i;
}
Thread.sleep(2000);
System.out.println("求和结束");
return sum;
}
}
执行结果:
开始求和
求和结束
主线程获得求和结果:49995000
举例二(Futuretask也可以使用ExecutorService执行)
public static void main(String[] args) {
CountSum countSum = new CountSum();// 创建一个Callable对象
FutureTask<Integer> futureTask = new FutureTask<>(countSum);// 创建FutureTask对象
ExecutorService executorService = Executors.newCachedThreadPool();// 开启线程
executorService.execute(futureTask);
try {
int sum = futureTask.get();
System.out.println("主线程获得求和结果:" + sum);
} catch (Exception e) {
e.printStackTrace();
futureTask.cancel(true);
} finally {
executorService.shutdown();
}
}
参考:https://www.jianshu.com/p/16d6f0a22111
https://www.toutiao.com/i6847669587702612492/?tt_from=weixin&utm_campaign=client_share&wxshare_count=1×tamp=1595402336&app=news_article&utm_source=weixin&utm_medium=toutiao_android&use_new_style=1&req_id=202007221518550100140481441F0A51AE&group_id=6847669587702612492
网友评论