<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ū)別

          共 6605字,需瀏覽 14分鐘

           ·

          2021-10-02 04:55

          來源:https://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

          • ListshutdownNow

          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)

          1. Kafka 3.0重磅發(fā)布,棄用 Java 8 的支持!

          2. Redis的keys命令到底有多慢?

          3. Java17,有史以來最快 JDK

          4. Kafka 面試必備知識點,加分項

          最近面試BAT,整理一份面試資料Java面試BATJ通關(guān)手冊,覆蓋了Java核心技術(shù)、JVM、Java并發(fā)、SSM、微服務(wù)、數(shù)據(jù)庫、數(shù)據(jù)結(jié)構(gòu)等等。

          獲取方式:點“在看”,關(guān)注公眾號并回復(fù) Java 領(lǐng)取,更多內(nèi)容陸續(xù)奉上。

          文章有幫助的話,在看,轉(zhuǎn)發(fā)吧。

          謝謝支持喲 (*^__^*)

          瀏覽 29
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

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

          手機掃一掃分享

          分享
          舉報
          <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>
                  大香伊人蕉视频 | 影音先锋福利资源91p | 无码高清在线看 | 亚洲视频免费 | 男人天堂超碰 |