1. 程式人生 > >Runnable、Callable、Executor、Future、FutureTask關係解讀

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 ---------------------