1. 程式人生 > >Java執行緒池及Future、Callable獲得執行緒返回結果

Java執行緒池及Future、Callable獲得執行緒返回結果



Java執行緒池及Future、Callable獲得執行緒返回結果【Java執行緒池系列2】

Java多執行緒程式設計中,經常使用的Thread的Runnable()雖然被經常使用,但其有一個弊端,就是因為無法直接獲取該執行緒的返回值,因為Runnable內的run方法,被定義為void型別,如果開發者需要線上程中處理耗時操作並獲得結果,那麼必須自己實現一套結果獲取的途徑,這其實增加了開發者的程式碼工作量,也可能會因為對執行緒的不熟悉,造成不必要的程式碼錯誤(執行緒的同步等等問題)。
可是,絕大多情況跑完Java的執行緒run後,並不是讓它啥都不幹的void,而是希望獲得執行結果。因此,從Java 

5開始,Java在語言層級增加了支援執行緒返回結果的Future、Callable,用以支援和解決上述問題,完事執行緒程式設計模型。

先丟出演示程式碼:

  1. package test_java;  
  2. import java.util.ArrayList;  
  3. import java.util.concurrent.Callable;  
  4. import java.util.concurrent.ExecutorService;  
  5. import java.util.concurrent.Executors;  
  6. import java.util.concurrent.Future;  
  7. public
    class ZhangPhilExecutorService {  
  8.     privatefinalint NUMBER = 3;  
  9.     public ZhangPhilExecutorService() {  
  10.         // 建立容量為NUMBER的執行緒池。
  11.         ExecutorService pool = Executors.newFixedThreadPool(NUMBER);  
  12.         ArrayList<Future<String>> futures = new ArrayList<Future<String>>();  
  13.         for (int i = 0; i < 10; i++) {  
  14.             AThread t = new AThread(i);  
  15.             Future<String> f = pool.submit(t);  
  16.             futures.add(f);  
  17.         }  
  18.         System.out.println("獲取結果中...");  
  19.         for (Future<String> f : futures) {  
  20.             try {  
  21.                 // if(f.isDone())
  22.                 System.out.println(f.get());  
  23.             } catch (Exception e) {  
  24.                 e.printStackTrace();  
  25.             }  
  26.         }  
  27.         System.out.println("得到結果.");  
  28.         // 關閉執行緒池。
  29.         pool.shutdown();  
  30.     }  
  31.     privateclass AThread implements Callable<String> {  
  32.         privateint id;  
  33.         public AThread(int id) {  
  34.             this.id = id;  
  35.         }  
  36.         @Override
  37.         public String call() {  
  38.             System.out.println("執行緒:" + id + " -> 執行...");  
  39.             try {  
  40.                 Thread.sleep(5000);  
  41.             } catch (Exception e) {  
  42.                 e.printStackTrace();  
  43.             }  
  44.             System.out.println("執行緒:" + id + " -> 結束.");  
  45.             return"返回的字串" + id;  
  46.         }  
  47.     }  
  48.     publicstaticvoid main(String[] args) {  
  49.         new ZhangPhilExecutorService();  
  50.     }  
  51. }  


程式碼很簡單。Java的Callable相當於原先執行緒中的Runnable,但與Runnable中的run()不同的是,Callable中的過載方法call()將返回自定義的泛型結果。
(第一步)首先要定義一個“執行緒”實現Callable,在Callable穿進去想要獲得的泛型結果。
(第二步)然後用Java執行緒池submit第一步實現的Callable。
(第三步)在第二步中,向Java執行緒池submit執行緒時候,返回的Future就是未來要獲取執行緒執行結果的“控制代碼”。在本例中,跑了10個執行緒,為了獲得這10個執行緒的結果,那麼就建一個Future的ArrayList維護Future。

注意:
(1)Future的get方法在獲取結果時候將進入阻塞,阻塞直到Callable中的call返回。
(2)如果不想使得get阻塞,那麼可以在get之前加一層判斷isDone(),如果完成就獲取,如果沒有則跳過。

Java執行緒池及Future、Callable獲得執行緒返回結果【Java執行緒池系列2】

Java多執行緒程式設計中,經常使用的Thread的Runnable()雖然被經常使用,但其有一個弊端,就是因為無法直接獲取該執行緒的返回值,因為Runnable內的run方法,被定義為void型別,如果開發者需要線上程中處理耗時操作並獲得結果,那麼必須自己實現一套結果獲取的途徑,這其實增加了開發者的程式碼工作量,也可能會因為對執行緒的不熟悉,造成不必要的程式碼錯誤(執行緒的同步等等問題)。
可是,絕大多情況跑完Java的執行緒run後,並不是讓它啥都不幹的void,而是希望獲得執行結果。因此,從Java 5開始,Java在語言層級增加了支援執行緒返回結果的Future、Callable,用以支援和解決上述問題,完事執行緒程式設計模型。

先丟出演示程式碼:

  1. package test_java;  
  2. import java.util.ArrayList;  
  3. import java.util.concurrent.Callable;  
  4. import java.util.concurrent.ExecutorService;  
  5. import java.util.concurrent.Executors;  
  6. import java.util.concurrent.Future;  
  7. publicclass ZhangPhilExecutorService {  
  8.     privatefinalint NUMBER = 3;  
  9.     public ZhangPhilExecutorService() {  
  10.         // 建立容量為NUMBER的執行緒池。
  11.         ExecutorService pool = Executors.newFixedThreadPool(NUMBER);  
  12.         ArrayList<Future<String>> futures = new ArrayList<Future<String>>();  
  13.         for (int i = 0; i < 10; i++) {  
  14.             AThread t = new AThread(i);  
  15.             Future<String> f = pool.submit(t);  
  16.             futures.add(f);  
  17.         }  
  18.         System.out.println("獲取結果中...");  
  19.         for (Future<String> f : futures) {  
  20.             try {  
  21.                 // if(f.isDone())
  22.                 System.out.println(f.get());  
  23.             } catch (Exception e) {  
  24.                 e.printStackTrace();  
  25.             }  
  26.         }  
  27.         System.out.println("得到結果.");  
  28.         // 關閉執行緒池。
  29.         pool.shutdown();  
  30.     }  
  31.     privateclass AThread implements Callable<String> {  
  32.         privateint id;  
  33.         public AThread(int id) {  
  34.             this.id = id;  
  35.         }  
  36.         @Override
  37.         public String call() {  
  38.             System.out.println("執行緒:" + id + " -> 執行...");  
  39.             try {  
  40.                 Thread.sleep(5000);  
  41.             } catch (Exception e) {  
  42.                 e.printStackTrace();  
  43.             }  
  44.             System.out.println("執行緒:" + id + " -> 結束.");  
  45.             return"返回的字串" + id;  
  46.         }  
  47.     }  
  48.     publicstaticvoid main(String[] args) {  
  49.         new ZhangPhilExecutorService();  
  50.     }  
  51. }  


程式碼很簡單。Java的Callable相當於原先執行緒中的Runnable,但與Runnable中的run()不同的是,Callable中的過載方法call()將返回自定義的泛型結果。
(第一步)首先要定義一個“執行緒”實現Callable,在Callable穿進去想要獲得的泛型結果。
(第二步)然後用Java執行緒池submit第一步實現的Callable。
(第三步)在第二步中,向Java執行緒池submit執行緒時候,返回的Future就是未來要獲取執行緒執行結果的“控制代碼”。在本例中,跑了10個執行緒,為了獲得這10個執行緒的結果,那麼就建一個Future的ArrayList維護Future。

注意:
(1)Future的get方法在獲取結果時候將進入阻塞,阻塞直到Callable中的call返回。
(2)如果不想使得get阻塞,那麼可以在get之前加一層判斷isDone(),如果完成就獲取,如果沒有則跳過。