優雅關閉線程池的方案

  • 咱們常常在項目中使用的線程池,可是是否關心過線程池的關閉呢,可能不少時候直接再項目中直接建立線程池讓它一直運行當任務執行結束不在須要了也不去關閉,這實際上是存在很是大的風險的,大量的線程常駐在後臺對系統資源的佔用是巨大的 ,甚至引起異常。因此在咱們平時使用線程池時須要注意優雅的關閉,這樣能夠保證資源的管控。
  • Java 中和關閉線程池相關的方法主要有以下:java

    • void shutdown()
    • List<Runnable> shutDownNow
    • boolean awaitTermination
    • boolean isShutDown
    • boolean isTerminated
  • 對於這些方法有着不一樣的使用和做用,下面咱們真的會這些不一樣的方法作詳細的介紹。

ShutDown

  • shutDown 方法從字面意思咱們能夠看到是中止關閉的意思,咱們先來看下面的一段代碼,首先咱們經過 ThreadPoolExecutor 來建立一個容量是10的無界線程池,與 FixedThreadPool 相似的,這裏手動建立能夠更好地理解線程池的建立。在後咱們提交一千個任務執行,再執行 shutdown 方法進行暫停。
public static void main(String[] args) throws InterruptedException {

        ExecutorService service = new ThreadPoolExecutor(
                10,
                10,
                0L,
                TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<>());

        for (int i = 0; i < 1000; i++) {
            service.submit(() ->{
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    System.out.println("接受中斷,不處理~~");
                }
                System.out.println("args = " + Arrays.deepToString(args)+ Thread.currentThread().getName());
            });
        }

        service.shutdown();
    }
  • 咱們能夠看到結果因此線程會正常執行結束後再關閉線程池,對於 ShutDown 而言它能夠安全的中止一個線程池,它有幾個關鍵點
  • ShutDown 會首先將線程設置成 SHUTDOWN 狀態,而後中斷全部沒有正在運行的線程
  • 正在執行的線程和已經在隊列中的線程並不會被中斷,說白了就是使用shutDown 方法其實就是要等待全部任務正常所有結束之後纔會關閉線程池
  • 調用 shutdown() 方法後若是還有新的任務被提交,線程池則會根據拒絕策略直接拒絕後續新提交的任務。

ShutDownNow

  • 這個方法與上面方法相比較,直觀就是 now ,即當即中止任務,
  • 一樣是上述案列,略做修改以下,
public static void main(String[] args) throws InterruptedException {

        ExecutorService service = new ThreadPoolExecutor(
                10,
                10,
                0L,
                TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<>(1000));

        for (int i = 0; i < 1000; i++) {
            service.submit(() ->{
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    System.out.println("接受中斷,結束線程~~");
                    //這裏響應中斷
                    return;
                }
                System.out.println("args = " + Arrays.deepToString(args)+ Thread.currentThread().getName());
            });
        }

      final List<Runnable> runnables = service.shutdownNow();
       System.out.println(runnables);
    }
  • 執行上述代碼咱們發現,當執行shutDownNow 方法後,會像所有正在運行的隊列通知中斷,正在運行的線程接收到中斷信號後選擇處理,而在隊列中的所有取消執行轉移到一個list隊列中返回,如上述 List<Runnable> runnables ,這裏記錄了全部終止的線程

awaitTermination

  • 這個方法並非用來關閉線程池的,首先咱們看一下這個方法的定義:
boolean awaitTermination_(_long timeout, TimeUnit unit_)_
  • 能夠看到這個方法有兩個參數,timeout 表示等待的時間,unit 時間單位
  • 這個方法的做用是,調用後等待timeout時間後,反饋線程池的狀態,
  • 等待期間(包括進入等待狀態以前)線程池已關閉而且全部已提交的任務(包括正在執行的和隊列中等待的)都執行完畢,至關於線程池已經「終結」了,方法便會返回 true
  • 等待超時時間到後,第一種線程池「終結」的狀況始終未發生,方法返回 false
  • 等待期間線程被中斷,方法會拋出 InterruptedException 異常。
  • 上面代碼能夠修改來測試,這裏再也不粘貼代碼

isShutDown

  • isShutDown 方法正如名字,判斷線程池是否中止,返回的是 Boolean 類型,若是已經開始中止線程池則返回 true 不然放回false
  • 當調用了shutDownshutDownNow 時以後,會返回 true 不過須要注意,這時候只是表明線程池關閉流程的開始,並非說線程池已經中止了

isTerminated

  • 這個方法與上面的方法的區別就是這是正真檢測線程池是否真的終結了
  • 這不只表明線程池已關閉,同時表明線程池中的全部任務都已經都執行完畢了,由於在調用 shutdown 方法以後,線程池會繼續執行裏面未完成的任務,包括正在執行的任務和在任務隊列中等待的任務。
  • 若是調用了 shutdown 方法,可是有一個線程依然在執行任務,那麼此時調用 isShutdown 方法返回的是 true,而調用 isTerminated方法返回的即是 false,由於線程池中還有任務正在在被執行,線程池並無真正「終結」。
  • 直到全部任務都執行完畢了,調用 isTerminated() 方法纔會返回 true,這表示線程池已關閉而且線程池內部是空的,全部剩餘的任務都執行完畢了。


本文由AnonyStar 發佈,可轉載但需聲明原文出處。
歡迎關注微信公帳號 :雲棲簡碼 獲取更多優質文章
更多文章關注筆者博客 : 雲棲簡碼 i-code.online
相關文章
相關標籤/搜索