0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

如何正確關(guān)閉線程池

Android編程精選 ? 來源:CSDN博客 ? 作者:不懂的浪漫 ? 2021-09-29 14:41 ? 次閱讀

前言本章分為兩個議題

如何正確關(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ù)。學習資料:Java進階視頻資源

這段源碼位置(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),并且把當前的任務(wù)從任務(wù)隊列中移除成功,則拒絕該任務(wù)

reject(command);

else if (workerCountOf(recheck) == 0)

// 如果之前的線程已經(jīng)被銷毀完,新建一個非核心線程

addWorker(null, false);

}

// 核心線程池已滿,隊列已滿,嘗試創(chuàng)建一個非核心新的線程

else if (!addWorker(command, false))

// 如果創(chuàng)建新線程失敗,說明線程池關(guān)閉或者線程池滿了,拒絕任務(wù)

reject(command);

}

1373 行 if (! isRunning(recheck) && remove(command))如果線程池被關(guān)閉,將當前的任務(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í)行完畢了。

學習資料:Java進階視頻資源

5.awaitTermination

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

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

等待期間(包括進入等待狀態(tài)之前)線程池已關(guān)閉并且所有已提交的任務(wù)(包括正在執(zhí)行的和隊列中等待的)都執(zhí)行完畢,相當于線程池已經(jīng)“終結(jié)”了,方法便會返回 true

等待超時時間到后,第一種線程池“終結(jié)”的情況始終未發(fā)生,方法返回 false

等待期間線程被中斷,方法會拋出 InterruptedException 異常

調(diào)用 awaitTermination 方法后當前線程會嘗試等待一段指定的時間,如果在等待時間內(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ù)期間檢測到中斷信號并進行相應的處理,提前結(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)

責任編輯:haq

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 模塊
    +關(guān)注

    關(guān)注

    7

    文章

    2613

    瀏覽量

    47016
  • 多線程
    +關(guān)注

    關(guān)注

    0

    文章

    275

    瀏覽量

    19850

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

文章出處:【微信號:AndroidPush,微信公眾號:Android編程精選】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    買藥秒送 JADE動態(tài)線程實踐及原理淺析

    一、背景及JADE介紹 買藥秒送是健康即時零售業(yè)務(wù)新的核心流量場域,面對京東首頁高流量曝光,我們對頻道頁整個技術(shù)架構(gòu)方案進行升級,保障接口高性能、系統(tǒng)高可用。 動態(tài)線程是買藥頻道應用的技術(shù)之一
    的頭像 發(fā)表于 09-04 11:11 ?660次閱讀
    買藥秒送 JADE動態(tài)<b class='flag-5'>線程</b><b class='flag-5'>池</b>實踐及原理淺析

    動態(tài)線程思想學習及實踐

    相關(guān)文檔 美團線程實踐:https://tech.meituan.com/2020/04/02/java-pooling-pratice-in-meituan.html 線程思想解
    的頭像 發(fā)表于 06-13 15:43 ?1028次閱讀
    動態(tài)<b class='flag-5'>線程</b><b class='flag-5'>池</b>思想學習及實踐

    什么是動態(tài)線程?動態(tài)線程的簡單實現(xiàn)思路

    因此,動態(tài)可監(jiān)控線程一種針對以上痛點開發(fā)的線程管理工具。主要可實現(xiàn)功能有:提供對 Spring 應用內(nèi)線程
    的頭像 發(fā)表于 02-28 10:42 ?470次閱讀

    線程的創(chuàng)建方式有幾種

    線程是一種用于管理和調(diào)度線程的技術(shù),能夠有效地提高系統(tǒng)的性能和資源利用率。它通過預先創(chuàng)建一組線程并維護一個工作隊列,將任務(wù)提交給線程
    的頭像 發(fā)表于 12-04 16:52 ?661次閱讀

    線程七大核心參數(shù)執(zhí)行順序

    線程是一種用于管理和調(diào)度線程執(zhí)行的技術(shù),通過將任務(wù)分配到線程池中的線程進行處理,可以有效地控制并發(fā)線程
    的頭像 發(fā)表于 12-04 16:45 ?746次閱讀

    核心線程數(shù)和最大線程數(shù)怎么設(shè)置

    。 一、核心線程數(shù)和最大線程數(shù)的定義與作用 核心線程數(shù)(Core Pool Size):指線程池中可以同時運行的線程的最小數(shù)量。即使提交更多
    的頭像 發(fā)表于 12-01 13:50 ?7475次閱讀

    線程三大核心參數(shù)的含義 線程核心線程數(shù)制定策略

    以上考點作為線程面試幾乎必問的內(nèi)容,大部分人應該都是如數(shù)家珍,張口就來,但是懂了面試八股文真的就不一定在實際運用中真的就會把線程用好 。
    的頭像 發(fā)表于 12-01 10:20 ?754次閱讀
    <b class='flag-5'>線程</b><b class='flag-5'>池</b>三大核心參數(shù)的含義 <b class='flag-5'>線程</b><b class='flag-5'>池</b>核心<b class='flag-5'>線程</b>數(shù)制定策略

    JDK如何優(yōu)雅退出一個線程

    需要線程退出的常見場景 任務(wù)執(zhí)行完成,或異常終止,任務(wù)認為無需再占用線程。 線程根據(jù)當前任務(wù)執(zhí)行情況,伸縮線程
    的頭像 發(fā)表于 11-17 10:02 ?361次閱讀
    JDK如何優(yōu)雅退出一個<b class='flag-5'>線程</b>?

    如何用C語言實現(xiàn)線程

    線程是一種多線程處理形式,大多用于高并發(fā)服務(wù)器上,它能合理有效的利用高并發(fā)服務(wù)器上的線程資源;線程與進程用于處理各項分支子功能,我們通常的
    的頭像 發(fā)表于 11-13 10:41 ?798次閱讀
    如何用C語言實現(xiàn)<b class='flag-5'>線程</b><b class='flag-5'>池</b>

    線程的基本概念

    線程的基本概念 不管線程是什么東西!但是我們必須知道線程被搞出來的目的就是:提高程序執(zhí)行效
    的頭像 發(fā)表于 11-10 16:37 ?428次閱讀
    <b class='flag-5'>線程</b><b class='flag-5'>池</b>的基本概念

    線程基本概念與原理

    一、線程基本概念與原理 1.1 線程概念及優(yōu)勢 C++線程簡介
    的頭像 發(fā)表于 11-10 10:24 ?408次閱讀

    了解連接、線程、內(nèi)存、異步請求

    可被重復使用像常見的線程、內(nèi)存、連接、對象都具有以上的共同特點。 連接 什么是數(shù)據(jù)庫連
    的頭像 發(fā)表于 11-09 14:44 ?870次閱讀
    了解連接<b class='flag-5'>池</b>、<b class='flag-5'>線程</b><b class='flag-5'>池</b>、內(nèi)存<b class='flag-5'>池</b>、異步請求<b class='flag-5'>池</b>

    Spring 的線程應用

    我們在日常開發(fā)中,經(jīng)常跟多線程打交道,Spring 為我們提供了一個線程方便我們開發(fā),它就是 ThreadPoolTaskExecutor ,接下來我們就來聊聊 Spring 的線程
    的頭像 發(fā)表于 10-13 10:47 ?523次閱讀
    Spring 的<b class='flag-5'>線程</b><b class='flag-5'>池</b>應用

    Java中的線程包括哪些

    線程是用來統(tǒng)一管理線程的,在 Java 中創(chuàng)建和銷毀線程都是一件消耗資源的事情,線程可以重復
    的頭像 發(fā)表于 10-11 15:33 ?730次閱讀
    Java中的<b class='flag-5'>線程</b><b class='flag-5'>池</b>包括哪些

    線程的兩個思考

    今天還是說一下線程的兩個思考。 池子 我們常用的線程, JDK的ThreadPoolExecutor. CompletableFutures 默認使用了
    的頭像 發(fā)表于 09-30 11:21 ?2938次閱讀
    <b class='flag-5'>線程</b><b class='flag-5'>池</b>的兩個思考