<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          正確關(guān)閉線程池:shutdown 和 shutdownNow 的區(qū)別

          共 7566字,需瀏覽 16分鐘

           ·

          2021-09-30 22:37

          來源:blog.csdn.net/xiewenfeng520/article/details/107013342

          前言

          本章分為兩個議題

          • 如何正確關(guān)閉線程池
          • shutdown 和 shutdownNow 的區(qū)別

          項目環(huán)境

          • jdk 1.8
          • github 地址:https://github.com/huajiexiewenfeng/java-concurrent
            • 本章模塊:threadpool

          1.線程池示例

          public class ShutDownThreadPoolDemo {

              private ExecutorService service = Executors.newFixedThreadPool(10);

              public static void main(String[] args) {
                  new ShutDownThreadPoolDemo().executeTask();
              }

              public void executeTask() {
                  for (int i = 0; i < 100; i++) {
                      service.submit(() -> {
                          System.out.println(Thread.currentThread().getName() + "->執(zhí)行");
                      });
                  }
              }

          }

          執(zhí)行結(jié)果

          pool-1-thread-2->執(zhí)行
          pool-1-thread-3->執(zhí)行
          pool-1-thread-1->執(zhí)行
          pool-1-thread-4->執(zhí)行
          pool-1-thread-5->執(zhí)行
          pool-1-thread-6->執(zhí)行
          ...

          執(zhí)行完成之后,主線程會一直阻塞,那么如何關(guān)閉線程池呢?本章介紹 5 種在 ThreadPoolExecutor 中涉及關(guān)閉線程池的方法,如下所示

          void shutdown
          boolean isShutdown
          boolean isTerminated
          boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException
          List<Runnable> shutdownNow

          2.shutdown

          第一種方法叫作 shutdown(),它可以安全地關(guān)閉一個線程池,調(diào)用 shutdown() 方法之后線程池并不是立刻就被關(guān)閉,因為這時線程池中可能還有很多任務(wù)正在被執(zhí)行,或是任務(wù)隊列中有大量正在等待被執(zhí)行的任務(wù),調(diào)用 shutdown() 方法后線程池會在執(zhí)行完正在執(zhí)行的任務(wù)和隊列中等待的任務(wù)后才徹底關(guān)閉。

          調(diào)用 shutdown() 方法后如果還有新的任務(wù)被提交,線程池則會根據(jù)拒絕策略直接拒絕后續(xù)新提交的任務(wù)。

          這段源碼位置(jdk 1.8 版本)

          • java.util.concurrent.ThreadPoolExecutor#execute
              public void execute(Runnable command) {
                  if (command == null)
                      throw new NullPointerException();
                  int c = ctl.get();
                  // 線程池中的線程比核心線程數(shù)少 
                  if (workerCountOf(c) < corePoolSize) {
                      // 新建一個核心線程執(zhí)行任務(wù)
                      if (addWorker(command, true))
                          return;
                      c = ctl.get();
                  }
                  // 核心線程已滿,但是任務(wù)隊列未滿,添加到隊列中
                  if (isRunning(c) && workQueue.offer(command)) {
                      int recheck = ctl.get();
                      // 任務(wù)成功添加到隊列以后,再次檢查是否需要添加新的線程,因為已存在的線程可能被銷毀了
                      if (! isRunning(recheck) && remove(command))
                          // 如果線程池處于非運行狀態(tài),并且把當(dāng)前的任務(wù)從任務(wù)隊列中移除成功,則拒絕該任務(wù)
                          reject(command);
                      else if (workerCountOf(recheck) == 0)
                          // 如果之前的線程已經(jīng)被銷毀完,新建一個非核心線程
                          addWorker(nullfalse);
                  }
                  // 核心線程池已滿,隊列已滿,嘗試創(chuàng)建一個非核心新的線程
                  else if (!addWorker(command, false))
                      // 如果創(chuàng)建新線程失敗,說明線程池關(guān)閉或者線程池滿了,拒絕任務(wù)
                      reject(command);
              }
          • 1373 行 if (! isRunning(recheck) && remove(command))如果線程池被關(guān)閉,將當(dāng)前的任務(wù)從任務(wù)隊列中移除成功,并拒絕該任務(wù)

          • 1378 行 else if (!addWorker(command, false))如果創(chuàng)建新線程失敗,說明線程池關(guān)閉或者線程池滿了,拒絕任務(wù)。

          3.isShutdown

          第二個方法叫作 isShutdown(),它可以返回 true 或者 false 來判斷線程池是否已經(jīng)開始了關(guān)閉工作,也就是是否執(zhí)行了 shutdown 或者 shutdownNow 方法。

          這里需要注意,如果調(diào)用 isShutdown() 方法的返回的結(jié)果為 true 并不代表線程池此時已經(jīng)徹底關(guān)閉了,這僅僅代表線程池開始了關(guān)閉的流程,也就是說,此時可能線程池中依然有線程在執(zhí)行任務(wù),隊列里也可能有等待被執(zhí)行的任務(wù)。

          4.isTerminated

          第三種方法叫作 isTerminated(),這個方法可以檢測線程池是否真正“終結(jié)”了,這不僅代表線程池已關(guān)閉,同時代表線程池中的所有任務(wù)都已經(jīng)都執(zhí)行完畢了。

          比如我們上面提到的情況,如果此時已經(jīng)調(diào)用了 shutdown 方法,但是還有任務(wù)沒有執(zhí)行完,那么此時調(diào)用 isShutdown 方法返回的是 true,而 isTerminated 方法則會返回 false。

          直到所有任務(wù)都執(zhí)行完畢了,調(diào)用 isTerminated() 方法才會返回 true,這表示線程池已關(guān)閉并且線程池內(nèi)部是空的,所有剩余的任務(wù)都執(zhí)行完畢了。

          5.awaitTermination

          第四個方法叫作 awaitTermination(),它本身并不是用來關(guān)閉線程池的,而是主要用來判斷線程池狀態(tài)的。

          比如我們給 awaitTermination 方法傳入的參數(shù)是 10 秒,那么它就會陷入 10 秒鐘的等待,直到發(fā)生以下三種情況之一:

          • 等待期間(包括進入等待狀態(tài)之前)線程池已關(guān)閉并且所有已提交的任務(wù)(包括正在執(zhí)行的和隊列中等待的)都執(zhí)行完畢,相當(dāng)于線程池已經(jīng)“終結(jié)”了,方法便會返回 true
          • 等待超時時間到后,第一種線程池“終結(jié)”的情況始終未發(fā)生,方法返回 false
          • 等待期間線程被中斷,方法會拋出 InterruptedException 異常

          調(diào)用 awaitTermination 方法后當(dāng)前線程會嘗試等待一段指定的時間,如果在等待時間內(nèi),線程池已關(guān)閉并且內(nèi)部的任務(wù)都執(zhí)行完畢了,也就是說線程池真正“終結(jié)”了,那么方法就返回 true,否則超時返回 fasle。

          6.shutdownNow

          最后一個方法是 shutdownNow(),它和 shutdown() 的區(qū)別就是多了一個 Now,表示立刻關(guān)閉的意思,不推薦使用這一種方式關(guān)閉線程池。

          在執(zhí)行 shutdownNow 方法之后,首先會給所有線程池中的線程發(fā)送 interrupt 中斷信號,嘗試中斷這些任務(wù)的執(zhí)行,然后會將任務(wù)隊列中正在等待的所有任務(wù)轉(zhuǎn)移到一個 List 中并返回,我們可以根據(jù)返回的任務(wù) List 來進行一些補救的操作,例如記錄在案并在后期重試。

          shutdownNow 源碼如下:

              public List<Runnable> shutdownNow() {
                  List<Runnable> tasks;
                  final ReentrantLock mainLock = this.mainLock;
                  mainLock.lock();
                  try {
                      checkShutdownAccess();
                      advanceRunState(STOP);
                      interruptWorkers();
                      tasks = drainQueue();
                  } finally {
                      mainLock.unlock();
                  }
                  tryTerminate();
                  return tasks;
              }
          • interruptWorkers

          讓每一個已經(jīng)啟動的線程都中斷,這樣線程就可以在執(zhí)行任務(wù)期間檢測到中斷信號并進行相應(yīng)的處理,提前結(jié)束任務(wù)

          7.shutdown 和 shutdownNow 的區(qū)別?

          shutdown 會等待線程池中的任務(wù)執(zhí)行完成之后關(guān)閉線程池,而 shutdownNow 會給所有線程發(fā)送中斷信號,中斷任務(wù)執(zhí)行,然后關(guān)閉線程池

          shutdown 沒有返回值,而 shutdownNow 會返回關(guān)閉前任務(wù)隊列中未執(zhí)行的任務(wù)集合(List)

          推薦閱讀:

          世界的真實格局分析,地球人類社會底層運行原理

          不是你需要中臺,而是一名合格的架構(gòu)師(附各大廠中臺建設(shè)PPT)

          企業(yè)IT技術(shù)架構(gòu)規(guī)劃方案

          論數(shù)字化轉(zhuǎn)型——轉(zhuǎn)什么,如何轉(zhuǎn)?

          華為干部與人才發(fā)展手冊(附PPT)

          企業(yè)10大管理流程圖,數(shù)字化轉(zhuǎn)型從業(yè)者必備!

          【中臺實踐】華為大數(shù)據(jù)中臺架構(gòu)分享.pdf

          華為的數(shù)字化轉(zhuǎn)型方法論

          華為如何實施數(shù)字化轉(zhuǎn)型(附PPT)

          超詳細280頁Docker實戰(zhàn)文檔!開放下載

          華為大數(shù)據(jù)解決方案(PPT)

          瀏覽 15
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  免费在线观看成人性爱视频 | 国产精品福利视频 | 一级片在线免费黄 | 蜜乳一区二区三区四区五区六区 | 韩国一级一级免费 |