能異步絕不同步,能並行絕不串行
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服務獲取,有的數據需要從緩存中讀取,有的數據需要復雜的計算)