1. 程式人生 > >(轉)ExecutorService物件的shutdown()和shutdownNow()的區別

(轉)ExecutorService物件的shutdown()和shutdownNow()的區別

 從上篇文章的例項中,我們用了ExecutorService的shutdown方法,但我們不難發現它還有shutdownNow方法,它們到底有什麼區別呢?

        這兩個方法都可以關閉 ExecutorService,這將導致其拒絕新任務。shutdown() 方法在終止前允許執行以前提交的任務,而 shutdownNow() 方法阻止等待任務啟動並試圖停止當前正在執行的任務。在終止時,執行程式沒有任務在執行,也沒有任務在等待執行,並且無法提交新任務。應該關閉未使用的 ExecutorService 以允許回收其資源。 

        下列方法分兩個階段關閉 ExecutorService。第一階段呼叫 shutdown 拒絕傳入任務,然後呼叫 shutdownNow(如有必要)取消所有遺留的任務:

Java程式碼 

 收藏程式碼

  1. private static void shutdownAndAwaitTermination(ExecutorService pool) {  
  2.     pool.shutdown(); // Disable new tasks from being submitted  
  3.     try {  
  4.         // Wait a while for existing tasks to terminate  
  5.         if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {  
  6.             pool.shutdownNow(); // Cancel currently executing tasks  
  7.             // Wait a while for tasks to respond to being cancelled  
  8.             if (!pool.awaitTermination(60, TimeUnit.SECONDS))  
  9.                 System.err.println("Pool did not terminate");  
  10.         }  
  11.     } catch (InterruptedException ie) {  
  12.         // (Re-)Cancel if current thread also interrupted  
  13.         pool.shutdownNow();  
  14.         // Preserve interrupt status  
  15.         Thread.currentThread().interrupt();  
  16.     }  
  17. }  

        下面我們以上篇文章的例項來做測試驗證:

1.在submit(task2)後shutdown()

Java程式碼 

 收藏程式碼

  1. package com.bijian.study;  
  2. import java.util.concurrent.Callable;  
  3. import java.util.concurrent.ExecutorService;  
  4. import java.util.concurrent.Executors;  
  5. import java.util.concurrent.Future;  
  6. /**  
  7.  * Callable 和 Future介面 
  8.  * Callable是類似於Runnable的介面,實現Callable介面的類和實現Runnable的類都是可被其它執行緒執行的任務。 
  9.  * Callable和Runnable有幾點不同: 
  10.  * (1)Callable規定的方法是call(),而Runnable規定的方法是run(). 
  11.  * (2)Callable的任務執行後可返回值,而Runnable的任務是不能返回值的。 
  12.  * (3)call()方法可丟擲異常,而run()方法是不能丟擲異常的。 
  13.  * (4)執行Callable任務可拿到一個Future物件,Future 表示非同步計算的結果。它提供了檢查計算是否完成的方法,以等待計算的完成,並檢索計算的結果。通過Future物件可瞭解任務執行情況,可取消任務的執行,還可獲取任務執行的結果。 
  14.  */  
  15. public class CallableAndFuture {  
  16.     public static class MyCallable implements Callable {  
  17.         private int flag = 0;  
  18.         public MyCallable(int flag) {  
  19.             this.flag = flag;  
  20.         }  
  21.         public String call() throws Exception {  
  22.             if (this.flag == 0) {  
  23.                 return "flag = 0";  
  24.             }  
  25.             if (this.flag == 1) {  
  26.                 try {  
  27.                     while (true) {  
  28.                         System.out.println("looping.");  
  29.                         Thread.sleep(2000);  
  30.                     }  
  31.                 } catch (InterruptedException e) {  
  32.                     System.out.println("Interrupted");  
  33.                 }  
  34.                 return "false";  
  35.             } else {  
  36.                 throw new Exception("Bad flag value!");  
  37.             }  
  38.         }  
  39.     }  
  40.     public static void main(String[] args) {  
  41.         // 定義3個Callable型別的任務  
  42.         MyCallable task1 = new MyCallable(0);  
  43.         MyCallable task2 = new MyCallable(1);  
  44.         MyCallable task3 = new MyCallable(2);  
  45.         // 建立一個執行任務的服務  
  46.         ExecutorService es = Executors.newFixedThreadPool(3);  
  47.         try {  
  48.             // 提交併執行任務,任務啟動時返回了一個Future物件,  
  49.             // 如果想得到任務執行的結果或者是異常可對這個Future物件進行操作  
  50.             Future future1 = es.submit(task1);  
  51.             // 獲得第一個任務的結果,如果呼叫get方法,當前執行緒會等待任務執行完畢後才往下執行  
  52.             System.out.println("task1: " + future1.get());  
  53.             Future future2 = es.submit(task2);  
  54.             es.shutdown();  
  55.             // 等待5秒後,再停止第二個任務。因為第二個任務進行的是無限迴圈  
  56.             Thread.sleep(5000);  
  57.             System.out.println("task2 cancel: " + future2.cancel(true));  
  58.             // 獲取第三個任務的輸出,因為執行第三個任務會引起異常  
  59.             // 所以下面的語句將引起異常的丟擲  
  60.             Future future3 = es.submit(task3);  
  61.             System.out.println("task3: " + future3.get());  
  62.         } catch (Exception e) {  
  63.             System.out.println(e.toString());  
  64.         }  
  65.         // 停止任務執行服務  
  66.         //es.shutdown();  
  67.     }  
  68. }  

        執行結果:

Text程式碼 

 收藏程式碼

  1. task1: flag = 0  
  2. looping.  
  3. looping.  
  4. looping.  
  5. task2 cancel: true  
  6. java.util.concurrent.RejectedExecutionException  
  7. Interrupted  

2.在submit(task2)後shutdownNow()

Java程式碼 

 收藏程式碼

  1. package com.bijian.study;  
  2. import java.util.concurrent.Callable;  
  3. import java.util.concurrent.ExecutorService;  
  4. import java.util.concurrent.Executors;  
  5. import java.util.concurrent.Future;  
  6. /**  
  7.  * Callable 和 Future介面 
  8.  * Callable是類似於Runnable的介面,實現Callable介面的類和實現Runnable的類都是可被其它執行緒執行的任務。 
  9.  * Callable和Runnable有幾點不同: 
  10.  * (1)Callable規定的方法是call(),而Runnable規定的方法是run(). 
  11.  * (2)Callable的任務執行後可返回值,而Runnable的任務是不能返回值的。 
  12.  * (3)call()方法可丟擲異常,而run()方法是不能丟擲異常的。 
  13.  * (4)執行Callable任務可拿到一個Future物件,Future 表示非同步計算的結果。它提供了檢查計算是否完成的方法,以等待計算的完成,並檢索計算的結果。通過Future物件可瞭解任務執行情況,可取消任務的執行,還可獲取任務執行的結果。 
  14.  */  
  15. public class CallableAndFuture {  
  16.     public static class MyCallable implements Callable {  
  17.         private int flag = 0;  
  18.         public MyCallable(int flag) {  
  19.             this.flag = flag;  
  20.         }  
  21.         public String call() throws Exception {  
  22.             if (this.flag == 0) {  
  23.                 return "flag = 0";  
  24.             }  
  25.             if (this.flag == 1) {  
  26.                 try {  
  27.                     while (true) {  
  28.                         System.out.println("looping.");  
  29.                         Thread.sleep(2000);  
  30.                     }  
  31.                 } catch (InterruptedException e) {  
  32.                     System.out.println("Interrupted");  
  33.                 }  
  34.                 return "false";  
  35.             } else {  
  36.                 throw new Exception("Bad flag value!");  
  37.             }  
  38.         }  
  39.     }  
  40.     public static void main(String[] args) {  
  41.         // 定義3個Callable型別的任務  
  42.         MyCallable task1 = new MyCallable(0);  
  43.         MyCallable task2 = new MyCallable(1);  
  44.         MyCallable task3 = new MyCallable(2);  
  45.         // 建立一個執行任務的服務  
  46.         ExecutorService es = Executors.newFixedThreadPool(3);  
  47.         try {  
  48.             // 提交併執行任務,任務啟動時返回了一個Future物件,  
  49.             // 如果想得到任務執行的結果或者是異常可對這個Future物件進行操作  
  50.             Future future1 = es.submit(task1);  
  51.             // 獲得第一個任務的結果,如果呼叫get方法,當前執行緒會等待任務執行完畢後才往下執行  
  52.             System.out.println("task1: " + future1.get());  
  53.             Future future2 = es.submit(task2);  
  54.             es.shutdownNow();  
  55.             // 等待5秒後,再停止第二個任務。因為第二個任務進行的是無限迴圈  
  56.             Thread.sleep(5000);  
  57.             System.out.println("task2 cancel: " + future2.cancel(true));  
  58.             // 獲取第三個任務的輸出,因為執行第三個任務會引起異常  
  59.             // 所以下面的語句將引起異常的丟擲  
  60.             Future future3 = es.submit(task3);  
  61.             System.out.println("task3: " + future3.get());  
  62.         } catch (Exception e) {  
  63.             System.out.println(e.toString());  
  64.         }  
  65.         // 停止任務執行服務  
  66.         //es.shutdown();  
  67.     }  
  68. }  

        執行結果:

Text程式碼 

 收藏程式碼

  1. task1: flag = 0  
  2. looping.  
  3. Interrupted  
  4. task2 cancel: false  
  5. java.util.concurrent.RejectedExecutionException  

        當然,我們也可以分兩個階段關閉 ExecutorService。第一階段呼叫 shutdown 拒絕傳入任務,然後呼叫 shutdownNow(如有必要)取消所有遺留的任務。修改此例項如下:

Java程式碼 

 收藏程式碼

  1. package com.bijian.study;  
  2. import java.util.concurrent.Callable;  
  3. import java.util.concurrent.ExecutorService;  
  4. import java.util.concurrent.Executors;  
  5. import java.util.concurrent.Future;  
  6. import java.util.concurrent.TimeUnit;  
  7. /**  
  8.  * Callable 和 Future介面 
  9.  * Callable是類似於Runnable的介面,實現Callable介面的類和實現Runnable的類都是可被其它執行緒執行的任務。 
  10.  * Callable和Runnable有幾點不同: 
  11.  * (1)Callable規定的方法是call(),而Runnable規定的方法是run(). 
  12.  * (2)Callable的任務執行後可返回值,而Runnable的任務是不能返回值的。 
  13.  * (3)call()方法可丟擲異常,而run()方法是不能丟擲異常的。 
  14.  * (4)執行Callable任務可拿到一個Future物件,Future 表示非同步計算的結果。它提供了檢查計算是否完成的方法,以等待計算的完成,並檢索計算的結果。通過Future物件可瞭解任務執行情況,可取消任務的執行,還可獲取任務執行的結果。 
  15.  */  
  16. public class CallableAndFuture {  
  17.     public static class MyCallable implements Callable {  
  18.         private int flag = 0;  
  19.         public MyCallable(int flag) {  
  20.             this.flag = flag;  
  21.         }  
  22.         public String call() throws Exception {  
  23.             if (this.flag == 0) {  
  24.                 return "flag = 0";  
  25.             }  
  26.             if (this.flag == 1) {  
  27.                 try {  
  28.                     while (true) {  
  29.                         System.out.println("looping.");  
  30.                         Thread.sleep(2000);  
  31.                     }  
  32.                 } catch (InterruptedException e) {  
  33.                     System.out.println("Interrupted");  
  34.                 }  
  35.                 return "false";  
  36.             } else {  
  37.                 throw new Exception("Bad flag value!");  
  38.             }  
  39.         }  
  40.     }  
  41.     public static void main(String[] args) {  
  42.         // 定義3個Callable型別的任務  
  43.         MyCallable task1 = new MyCallable(0);  
  44.         MyCallable task2 = new MyCallable(1);  
  45.         MyCallable task3 = new MyCallable(2);  
  46.         // 建立一個執行任務的服務  
  47.         ExecutorService es = Executors.newFixedThreadPool(3);  
  48.         try {  
  49.             // 提交併執行任務,任務啟動時返回了一個Future物件,  
  50.             // 如果想得到任務執行的結果或者是異常可對這個Future物件進行操作  
  51.             Future future1 = es.submit(task1);  
  52.             // 獲得第一個任務的結果,如果呼叫get方法,當前執行緒會等待任務執行完畢後才往下執行  
  53.             System.out.println("task1: " + future1.get());  
  54.             Future future2 = es.submit(task2);  
  55.             shutdownAndAwaitTermination(es);  
  56.             // 等待5秒後,再停止第二個任務。因為第二個任務進行的是無限迴圈  
  57.             Thread.sleep(5000);  
  58.             System.out.println("task2 cancel: " + future2.cancel(true));  
  59.             // 獲取第三個任務的輸出,因為執行第三個任務會引起異常  
  60.             // 所以下面的語句將引起異常的丟擲  
  61.             Future future3 = es.submit(task3);  
  62.             System.out.println("task3: " + future3.get());  
  63.         } catch (Exception e) {  
  64.             System.out.println(e.toString());  
  65.         }  
  66.         // 停止任務執行服務  
  67.         //es.shutdown();  
  68.     }  
  69.     private static void shutdownAndAwaitTermination(ExecutorService pool) {  
  70.         pool.shutdown(); // Disable new tasks from being submitted  
  71.         try {  
  72.             // Wait a while for existing tasks to terminate  
  73.             if (!pool.awaitTermination(10, TimeUnit.SECONDS)) {  
  74.                 pool.shutdownNow(); // Cancel currently executing tasks  
  75.                 // Wait a while for tasks to respond to being cancelled  
  76.                 if (!pool.awaitTermination(10, TimeUnit.SECONDS))  
  77.                     System.err.println("Pool did not terminate");  
  78.             }  
  79.         } catch (InterruptedException ie) {  
  80.             // (Re-)Cancel if current thread also interrupted  
  81.             pool.shutdownNow();  
  82.             // Preserve interrupt status  
  83.             Thread.currentThread().interrupt();  
  84.         }  
  85.     }  
  86. }  

        執行結果:

Text程式碼 

 收藏程式碼

  1. task1: flag = 0  
  2. looping.  
  3. looping.  
  4. looping.  
  5. looping.  
  6. looping.  
  7. looping.  
  8. Interrupted  
  9. task2 cancel: false  
  10. java.util.concurrent.RejectedExecutionException