高併發程式設計-非同步-回顧-Callable&Future&FutureTask
高併發程式設計-非同步-回顧-Callable&Future&FutureTask
一、Callable&Future&FutureTask簡介
傳統的非同步操作通過Thread和Runnable建立執行緒,但是這兩種方法都面臨的一個問題就是沒有返回值,所以在JDK1.5之後提供了Callable介面來實現,Futrue和FutureTask就是配合Callable來使用的。
Callable和Runnable的程式碼對比
@FunctionalInterface public interface Runnable { /** **/ public abstract void run(); } @FunctionalInterface public interface Callable<V> { /** * *丟擲異常 */ V call() throws Exception; }
Runnable 的缺陷:
- 沒有返回值
- 不能檢查丟擲異常
Callable的call方法可以有返回值的,也可以定義丟擲的Exception,一般和Futrue配合使用,Futrue來監督任務的執行情況,取消任務,還可以獲取任務的執行結果。這是Callable比Runnable強大的地方
例項程式碼如下
public class ThreadTask { @SneakyThrows public static void main(String[] args) { new Thread(new Runnable() { @Override public void run() { System.out.println("開始執行Runnable"); } }).start();
FutureTask task= new FutureTask(new Callable() { @Override public Object call() throws Exception { System.out.println("開始執行Callable"); Thread.sleep(3000); return "返回任務結果"; } }); new Thread(task).start(); System.out.println(task.get()); } }
二、Futrue的主要功能
Futrue的主要功能是對Callable任務的監督,取消、獲取結果,可以通過task.get()獲取結果,這個時候會一直阻塞,直到任務返回執行結果為止。
futrue提供的方法如下:
- boolean cancel (boolean mayInterruptIfRunning) 取消任務的執行。引數指定是 否立即中斷任務執行,或者等等任務結束
- boolean isCancelled () 任務是否已經取消,任務正常完成前將其取消,則返回 true
- boolean isDone () 任務是否已經完成。需要注意的是如果任務正常終止、異常或 取消,都將返回true
- V get () throws InterruptedException, ExecutionException 等待任務執行結束,然後獲得V型別的結果。InterruptedException 執行緒被中斷異常,ExecutionException任務執行異常,如果任務被取消,還會丟擲 CancellationException
- V get (long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException 同上面的get功能一樣,多了設定超時時間。 引數timeout指定超時時間,uint指定時間的單位,在列舉類TimeUnit中有相關的定 義。如果計算超時,將丟擲TimeoutException
三、利用 FutureTask 建立 Future
Futrue本質上採用FutureTask來實現的,可以把他理解為生產者和消費者的一箇中轉站,FutureTask把任務儲存任務的結果,同時更新狀態:未執行、正在處理、已完成等
使用方法如下:
public class FutureTaskDemo { @SneakyThrows public static void main(String[] args) { Task task=new Task(); FutureTask<Integer> futureTask = new FutureTask<>(task); //作為執行緒入參 new Thread(futureTask).start(); //獲取執行結果 System.out.println(futureTask.get()); }
static class Task implements Callable<Integer> { @Override public Integer call() throws Exception { System.out.println("當前子執行緒執行緒名稱"+Thread.currentThread().getName()); int sum=0; for (int i = 0; i <100 ; i++) { sum+=1; } return sum; } } }
四、使用案例:塔機檢測的繫結錄入
在塔基錄入的時候,需要關聯黑匣子、關聯司機、繫結吊鉤視訊、繫結駕駛艙視訊,假設這些業務每個執行需要100ms,如果採用傳統的同步執行方式,需要400ms才能完成。如果採用Future的非同步執行,只需要100ms。
如下圖所示
示例程式碼如下:
public class FutureTaskDemoTwo { @SneakyThrows public static void main(String[] args) { FutureTask<String> ft1 = new FutureTask<>(new Task1()); FutureTask<String> ft2 = new FutureTask<>(new Task2()); FutureTask<String> ft3 = new FutureTask<>(new Task3()); FutureTask<String> ft4 = new FutureTask<>(new Task4()); //構建執行緒池 ExecutorService executorService= Executors.newFixedThreadPool(5); executorService.submit(ft1); executorService.submit(ft2); executorService.submit(ft3); executorService.submit(ft4); //獲取執行結果 System.out.println(ft1.get()); System.out.println(ft2.get()); System.out.println(ft3.get()); System.out.println(ft4.get()); } static class Task1 implements Callable<String> { @Override public String call() throws Exception { System.out.println("關聯黑匣子"); Thread.sleep(50); return "關聯黑匣子成功"; } } static class Task2 implements Callable<String> { @Override public String call() throws Exception { System.out.println("關聯司機"); Thread.sleep(50); return "關聯司機成功"; } } static class Task3 implements Callable<String> { @Override public String call() throws Exception { System.out.println("關聯吊鉤視訊"); Thread.sleep(50); return "關聯吊鉤視訊成功"; } } static class Task4 implements Callable<String> { @Override public String call() throws Exception { System.out.println("關聯駕駛艙視訊"); Thread.sleep(50); return "關聯駕駛艙視訊成功"; } } }
五、Futrue的缺陷
Futrue是個非同步計算結果,通過isDown來檢查非同步是否完成,通過get來獲取返回的結果。在非同步的計算中Futrue是比較合適的,但是也有很多不足之處:
- 任務阻塞:Future只提供了get()方法來獲取結果,並且是阻塞的,遇到了只能等待;
- 無法鏈式呼叫:如果你希望在計算任務完成後執行特定動作,不能滿足。
- 無法多工組合:如果你運行了多個任務,並期望在它們全部執行結束後執行特 定動作,那麼在Future中這是無能為力的;
- 無異常處理