Runnable、Callable、Executor、Future、FutureTask關係解讀
在再度溫習Java5的併發程式設計的知識點時發現,首要的就是把Runnable、Callable、Executor、Future等的關係搞明白,遂有了下述小測試程式,通過這個例子上述三者的關係就一目瞭然了。
在java5以後,一個可以排程執行的執行緒單元可以有三種方式定義:
Thread、Runnable、Callable,其中Runnable實現的是void run()方法,Callable實現的是 V call()方法,並且可以返回執行結果,其中Runnable可以提交給Thread來包裝下,直接啟動一個執行緒來執行,而Callable則一般都是提交給ExecuteService來執行。
簡單來說,Executor就是Runnable和Callable的排程容器,Future就是對於具體的排程任務的執行結果進行檢視,最為關鍵的是Future可以檢查對應的任務是否已經完成,也可以阻塞在get方法上一直等待任務返回結果。Runnable和Callable的差別就是Runnable是沒有結果可以返回的,就算是通過Future也看不到任務排程的結果的。
/** * 通過簡單的測試程式來試驗Runnable、Callable通過Executor來排程的時候與Future的關係 */ package com.hadoop.thread; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class RunnableAndCallable2Future { public static void main(String[] args) { // 建立一個執行任務的服務 ExecutorService executor = Executors.newFixedThreadPool(3); try { //1.Runnable通過Future返回結果為空 //建立一個Runnable,來排程,等待任務執行完畢,取得返回結果 Future<?> runnable1 = executor.submit(new Runnable() { @Override public void run() { System.out.println("runnable1 running."); } }); System.out.println("Runnable1:" + runnable1.get()); // 2.Callable通過Future能返回結果 //提交併執行任務,任務啟動時返回了一個 Future物件, // 如果想得到任務執行的結果或者是異常可對這個Future物件進行操作 Future<String> future1 = executor.submit(new Callable<String>() { @Override public String call() throws Exception { // TODO Auto-generated method stub return "result=task1"; } }); // 獲得任務的結果,如果呼叫get方法,當前執行緒會等待任務執行完畢後才往下執行 System.out.println("task1: " + future1.get()); //3. 對Callable呼叫cancel可以對對該任務進行中斷 //提交併執行任務,任務啟動時返回了一個 Future物件, // 如果想得到任務執行的結果或者是異常可對這個Future物件進行操作 Future<String> future2 = executor.submit(new Callable<String>() { @Override public String call() throws Exception { try { while (true) { System.out.println("task2 running."); Thread.sleep(50); } } catch (InterruptedException e) { System.out.println("Interrupted task2."); } return "task2=false"; } }); // 等待5秒後,再停止第二個任務。因為第二個任務進行的是無限迴圈 Thread.sleep(10); System.out.println("task2 cancel: " + future2.cancel(true)); // 4.用Callable時丟擲異常則Future什麼也取不到了 // 獲取第三個任務的輸出,因為執行第三個任務會引起異常 // 所以下面的語句將引起異常的丟擲 Future<String> future3 = executor.submit(new Callable<String>() { @Override public String call() throws Exception { throw new Exception("task3 throw exception!"); } }); System.out.println("task3: " + future3.get()); } catch (Exception e) { System.out.println(e.toString()); } // 停止任務執行服務 executor.shutdownNow(); } } 執行結果如下:
runnable1 running. Runnable1:null task1: result=task1 task2 running. task2 cancel: true Interrupted task2. java.util.concurrent.ExecutionException: java.lang.Exception: Bad flag value! FutureTask則是一個RunnableFuture<V>,即實現了Runnbale又實現了Futrue<V>這兩個介面,另外它還可以包裝Runnable和Callable<V>,所以一般來講是一個符合體了,它可以通過Thread包裝來直接執行,也可以提交給ExecuteService來執行,並且還可以通過v get()返回執行結果,線上程體沒有執行完成的時候,主執行緒一直阻塞等待,執行完則直接返回結果。
public class FutureTaskTest { /** * @param args */ public static void main(String[] args) { Callable<String> task = new Callable<String>() { public String call() { System.out.println("Sleep start."); try { Thread.sleep(1000 * 10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("Sleep end."); return "time=" + System.currentTimeMillis(); } }; //直接使用Thread的方式執行 FutureTask<String> ft = new FutureTask<String>(task); Thread t = new Thread(ft); t.start(); try { System.out.println("waiting execute result"); System.out.println("result = " + ft.get()); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ExecutionException e) { // TODO Auto-generated catch block e.printStackTrace(); } //使用Executors來執行 System.out.println("========="); FutureTask<String> ft2 = new FutureTask<String>(task); Executors.newSingleThreadExecutor().submit(ft2); try { System.out.println("waiting execute result"); System.out.println("result = " + ft2.get()); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ExecutionException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
執行結果如下: waiting execute result Sleep start. Sleep end. result = time=1370844662537 ========= waiting execute result Sleep start. Sleep end. result = time=1370844672542 ---------------------