(轉)ExecutorService物件的shutdown()和shutdownNow()的區別
阿新 • • 發佈:2018-12-14
從上篇文章的例項中,我們用了ExecutorService的shutdown方法,但我們不難發現它還有shutdownNow方法,它們到底有什麼區別呢?
這兩個方法都可以關閉 ExecutorService,這將導致其拒絕新任務。shutdown() 方法在終止前允許執行以前提交的任務,而 shutdownNow() 方法阻止等待任務啟動並試圖停止當前正在執行的任務。在終止時,執行程式沒有任務在執行,也沒有任務在等待執行,並且無法提交新任務。應該關閉未使用的 ExecutorService 以允許回收其資源。
下列方法分兩個階段關閉 ExecutorService。第一階段呼叫 shutdown 拒絕傳入任務,然後呼叫 shutdownNow(如有必要)取消所有遺留的任務:
Java程式碼
- private static void shutdownAndAwaitTermination(ExecutorService pool) {
- pool.shutdown(); // Disable new tasks from being submitted
- try {
- // Wait a while for existing tasks to terminate
- if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
- pool.shutdownNow(); // Cancel currently executing tasks
- // Wait a while for tasks to respond to being cancelled
- if (!pool.awaitTermination(60, TimeUnit.SECONDS))
- System.err.println("Pool did not terminate");
- }
- } catch (InterruptedException ie) {
- // (Re-)Cancel if current thread also interrupted
- pool.shutdownNow();
- // Preserve interrupt status
- Thread.currentThread().interrupt();
- }
- }
下面我們以上篇文章的例項來做測試驗證:
1.在submit(task2)後shutdown()
Java程式碼
- package com.bijian.study;
- import java.util.concurrent.Callable;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- import java.util.concurrent.Future;
- /**
- * Callable 和 Future介面
- * Callable是類似於Runnable的介面,實現Callable介面的類和實現Runnable的類都是可被其它執行緒執行的任務。
- * Callable和Runnable有幾點不同:
- * (1)Callable規定的方法是call(),而Runnable規定的方法是run().
- * (2)Callable的任務執行後可返回值,而Runnable的任務是不能返回值的。
- * (3)call()方法可丟擲異常,而run()方法是不能丟擲異常的。
- * (4)執行Callable任務可拿到一個Future物件,Future 表示非同步計算的結果。它提供了檢查計算是否完成的方法,以等待計算的完成,並檢索計算的結果。通過Future物件可瞭解任務執行情況,可取消任務的執行,還可獲取任務執行的結果。
- */
- public class CallableAndFuture {
- public static class MyCallable implements Callable {
- private int flag = 0;
- public MyCallable(int flag) {
- this.flag = flag;
- }
- public String call() throws Exception {
- if (this.flag == 0) {
- return "flag = 0";
- }
- if (this.flag == 1) {
- try {
- while (true) {
- System.out.println("looping.");
- Thread.sleep(2000);
- }
- } catch (InterruptedException e) {
- System.out.println("Interrupted");
- }
- return "false";
- } else {
- throw new Exception("Bad flag value!");
- }
- }
- }
- public static void main(String[] args) {
- // 定義3個Callable型別的任務
- MyCallable task1 = new MyCallable(0);
- MyCallable task2 = new MyCallable(1);
- MyCallable task3 = new MyCallable(2);
- // 建立一個執行任務的服務
- ExecutorService es = Executors.newFixedThreadPool(3);
- try {
- // 提交併執行任務,任務啟動時返回了一個Future物件,
- // 如果想得到任務執行的結果或者是異常可對這個Future物件進行操作
- Future future1 = es.submit(task1);
- // 獲得第一個任務的結果,如果呼叫get方法,當前執行緒會等待任務執行完畢後才往下執行
- System.out.println("task1: " + future1.get());
- Future future2 = es.submit(task2);
- es.shutdown();
- // 等待5秒後,再停止第二個任務。因為第二個任務進行的是無限迴圈
- Thread.sleep(5000);
- System.out.println("task2 cancel: " + future2.cancel(true));
- // 獲取第三個任務的輸出,因為執行第三個任務會引起異常
- // 所以下面的語句將引起異常的丟擲
- Future future3 = es.submit(task3);
- System.out.println("task3: " + future3.get());
- } catch (Exception e) {
- System.out.println(e.toString());
- }
- // 停止任務執行服務
- //es.shutdown();
- }
- }
執行結果:
Text程式碼
- task1: flag = 0
- looping.
- looping.
- looping.
- task2 cancel: true
- java.util.concurrent.RejectedExecutionException
- Interrupted
2.在submit(task2)後shutdownNow()
Java程式碼
- package com.bijian.study;
- import java.util.concurrent.Callable;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- import java.util.concurrent.Future;
- /**
- * Callable 和 Future介面
- * Callable是類似於Runnable的介面,實現Callable介面的類和實現Runnable的類都是可被其它執行緒執行的任務。
- * Callable和Runnable有幾點不同:
- * (1)Callable規定的方法是call(),而Runnable規定的方法是run().
- * (2)Callable的任務執行後可返回值,而Runnable的任務是不能返回值的。
- * (3)call()方法可丟擲異常,而run()方法是不能丟擲異常的。
- * (4)執行Callable任務可拿到一個Future物件,Future 表示非同步計算的結果。它提供了檢查計算是否完成的方法,以等待計算的完成,並檢索計算的結果。通過Future物件可瞭解任務執行情況,可取消任務的執行,還可獲取任務執行的結果。
- */
- public class CallableAndFuture {
- public static class MyCallable implements Callable {
- private int flag = 0;
- public MyCallable(int flag) {
- this.flag = flag;
- }
- public String call() throws Exception {
- if (this.flag == 0) {
- return "flag = 0";
- }
- if (this.flag == 1) {
- try {
- while (true) {
- System.out.println("looping.");
- Thread.sleep(2000);
- }
- } catch (InterruptedException e) {
- System.out.println("Interrupted");
- }
- return "false";
- } else {
- throw new Exception("Bad flag value!");
- }
- }
- }
- public static void main(String[] args) {
- // 定義3個Callable型別的任務
- MyCallable task1 = new MyCallable(0);
- MyCallable task2 = new MyCallable(1);
- MyCallable task3 = new MyCallable(2);
- // 建立一個執行任務的服務
- ExecutorService es = Executors.newFixedThreadPool(3);
- try {
- // 提交併執行任務,任務啟動時返回了一個Future物件,
- // 如果想得到任務執行的結果或者是異常可對這個Future物件進行操作
- Future future1 = es.submit(task1);
- // 獲得第一個任務的結果,如果呼叫get方法,當前執行緒會等待任務執行完畢後才往下執行
- System.out.println("task1: " + future1.get());
- Future future2 = es.submit(task2);
- es.shutdownNow();
- // 等待5秒後,再停止第二個任務。因為第二個任務進行的是無限迴圈
- Thread.sleep(5000);
- System.out.println("task2 cancel: " + future2.cancel(true));
- // 獲取第三個任務的輸出,因為執行第三個任務會引起異常
- // 所以下面的語句將引起異常的丟擲
- Future future3 = es.submit(task3);
- System.out.println("task3: " + future3.get());
- } catch (Exception e) {
- System.out.println(e.toString());
- }
- // 停止任務執行服務
- //es.shutdown();
- }
- }
執行結果:
Text程式碼
- task1: flag = 0
- looping.
- Interrupted
- task2 cancel: false
- java.util.concurrent.RejectedExecutionException
當然,我們也可以分兩個階段關閉 ExecutorService。第一階段呼叫 shutdown 拒絕傳入任務,然後呼叫 shutdownNow(如有必要)取消所有遺留的任務。修改此例項如下:
Java程式碼
- package com.bijian.study;
- import java.util.concurrent.Callable;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- import java.util.concurrent.Future;
- import java.util.concurrent.TimeUnit;
- /**
- * Callable 和 Future介面
- * Callable是類似於Runnable的介面,實現Callable介面的類和實現Runnable的類都是可被其它執行緒執行的任務。
- * Callable和Runnable有幾點不同:
- * (1)Callable規定的方法是call(),而Runnable規定的方法是run().
- * (2)Callable的任務執行後可返回值,而Runnable的任務是不能返回值的。
- * (3)call()方法可丟擲異常,而run()方法是不能丟擲異常的。
- * (4)執行Callable任務可拿到一個Future物件,Future 表示非同步計算的結果。它提供了檢查計算是否完成的方法,以等待計算的完成,並檢索計算的結果。通過Future物件可瞭解任務執行情況,可取消任務的執行,還可獲取任務執行的結果。
- */
- public class CallableAndFuture {
- public static class MyCallable implements Callable {
- private int flag = 0;
- public MyCallable(int flag) {
- this.flag = flag;
- }
- public String call() throws Exception {
- if (this.flag == 0) {
- return "flag = 0";
- }
- if (this.flag == 1) {
- try {
- while (true) {
- System.out.println("looping.");
- Thread.sleep(2000);
- }
- } catch (InterruptedException e) {
- System.out.println("Interrupted");
- }
- return "false";
- } else {
- throw new Exception("Bad flag value!");
- }
- }
- }
- public static void main(String[] args) {
- // 定義3個Callable型別的任務
- MyCallable task1 = new MyCallable(0);
- MyCallable task2 = new MyCallable(1);
- MyCallable task3 = new MyCallable(2);
- // 建立一個執行任務的服務
- ExecutorService es = Executors.newFixedThreadPool(3);
- try {
- // 提交併執行任務,任務啟動時返回了一個Future物件,
- // 如果想得到任務執行的結果或者是異常可對這個Future物件進行操作
- Future future1 = es.submit(task1);
- // 獲得第一個任務的結果,如果呼叫get方法,當前執行緒會等待任務執行完畢後才往下執行
- System.out.println("task1: " + future1.get());
- Future future2 = es.submit(task2);
- shutdownAndAwaitTermination(es);
- // 等待5秒後,再停止第二個任務。因為第二個任務進行的是無限迴圈
- Thread.sleep(5000);
- System.out.println("task2 cancel: " + future2.cancel(true));
- // 獲取第三個任務的輸出,因為執行第三個任務會引起異常
- // 所以下面的語句將引起異常的丟擲
- Future future3 = es.submit(task3);
- System.out.println("task3: " + future3.get());
- } catch (Exception e) {
- System.out.println(e.toString());
- }
- // 停止任務執行服務
- //es.shutdown();
- }
- private static void shutdownAndAwaitTermination(ExecutorService pool) {
- pool.shutdown(); // Disable new tasks from being submitted
- try {
- // Wait a while for existing tasks to terminate
- if (!pool.awaitTermination(10, TimeUnit.SECONDS)) {
- pool.shutdownNow(); // Cancel currently executing tasks
- // Wait a while for tasks to respond to being cancelled
- if (!pool.awaitTermination(10, TimeUnit.SECONDS))
- System.err.println("Pool did not terminate");
- }
- } catch (InterruptedException ie) {
- // (Re-)Cancel if current thread also interrupted
- pool.shutdownNow();
- // Preserve interrupt status
- Thread.currentThread().interrupt();
- }
- }
- }
執行結果:
Text程式碼
- task1: flag = 0
- looping.
- looping.
- looping.
- looping.
- looping.
- looping.
- Interrupted
- task2 cancel: false
- java.util.concurrent.RejectedExecutionException