FutureTask
能异步绝不同步,能并行绝不串行
1. Future
一个Future代表一个异步计算的结果。Future提供检查计算是否完成、等待计算完成并获取计算结果的方法。只有当计算完成以后,才可以使用get方法检索结果,否则将会阻塞直到计算完成。通过调研cancel方法可以取消执行。另外,还提供了检查任务是正常完成还是被取消的方法。一旦计算完成,这个计算不能被取消。
简单用法:
1 public class App {
2 ExecutorService executorService = Executors.newFixedThreadPool(3);
3 ArchiveSearcher searcher = new ArchiveSearcher();
4
5 void showSearch(final String target) throws InterruptedException {
6 Future<String> future = executorService.submit(new Callable<String>() {
7 public String call() {
8 return searcher.search(target);
9 }
10 });
11
12 displayOtherThings(); // do other things while searching
13
14 try {
15 displayText(future.get()); // use future
16 } catch (ExecutionException ex) {
17 cleanup();
18 return;
19 }
20 }
21 }
FutureTask类是Future的实现,它同时也实现了Runnable,因此也可以被Executor执行。例如,上面的代码可以被改写成如下:
1 FutureTask<String> future = new FutureTask<String>(new Callable<String>() {
2 public String call() {
3 return searcher.search(target);
4 }
5 });
6 executor.execute(future);
2. FutureTask
- 一个可取消的异步计算
- 该类提供了Future的基本实现,提供了启动和取消计算、查询计算是否完成以及检索计算结果的方法
- 只有在计算完成后才可检索结果;如果计算尚未完成,get方法将阻塞
- 计算完成以后,计算不能重启或取消(除非调用runAndReset方法)
一个FutureTask可以用来包装一个Callable或Runnable对象。因为FutureTask实现了Runnable接口,一个FutureTask可以被提交给一个Executor来执行。
3. 示例
1 package com.cjs.example;
2
3 import java.util.concurrent.*;
4
5 /**
6 * @author ChengJianSheng
7 * @date 2019-05-22
8 */
9 public class App {
10
11 public static void main(String[] args) throws Exception {
12
13 long t1 = System.currentTimeMillis();
14
15 ExecutorService executorService = Executors.newFixedThreadPool(3);
16
17 FutureTask<String> heatUpWaterFuture = new FutureTask<String>(new Callable<String>() {
18 @Override
19 public String call() throws Exception {
20 System.out.println("烧开水...");
21 Thread.sleep(3000);
22 return "ok";
23 }
24 });
25
26
27 FutureTask<String> cookMealsFuture = new FutureTask<String>(new Callable<String>() {
28 @Override
29 public String call() throws Exception {
30 System.out.println("煮饭...");
31 Thread.sleep(5000);
32 return "ok";
33 }
34 });
35
36 executorService.submit(heatUpWaterFuture);
37 executorService.submit(cookMealsFuture);
38
39 System.out.println("炒菜...");
40
41 Thread.sleep(2000);
42
43 System.out.println("菜炒好了了");
44
45 if (heatUpWaterFuture.get(5000, TimeUnit.SECONDS) == "ok"
46 && cookMealsFuture.get(5000, TimeUnit.SECONDS) == "ok") {
47 System.out.println("开饭了...");
48 }
49
50 long t2 = System.currentTimeMillis();
51 System.out.println("做饭用时:" + (t2-t1) + "ms");
52
53 }
54 }
输出
1 烧开水...
2 煮饭...
3 炒菜...
4 菜炒好了了
5 开饭了...
6 做饭用时:5014ms
在实际开发过程中,将那些耗时较长,且可以并行的操作都封装成一个FutureTask(比如:有的数据通过调用dubbo服务获取,有的数据需要从缓存中读取,有的数据需要复杂的计算)