最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解Java線程池如何實(shí)現(xiàn)優(yōu)雅退出

 更新時(shí)間:2022年07月18日 15:26:37   作者:冰_河  
這篇文章我們將從源碼角度深度解析線程池是如何優(yōu)雅的退出程序的,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)java線程池有一定幫助,需要的可以參考一下

在【高并發(fā)專題】中,我們從源碼角度深度分析了線程池中那些重要的接口和抽象類、深度解析了線程池是如何創(chuàng)建的,ThreadPoolExecutor類有哪些屬性和內(nèi)部類,以及它們對(duì)線程池的重要作用。深度分析了線程池的整體核心流程,以及如何拆解Worker線程的執(zhí)行代碼,深度解析Worker線程的執(zhí)行流程。

本文,我們就來從源碼角度深度解析線程池是如何優(yōu)雅的退出程序的。首先,我們來看下ThreadPoolExecutor類中的shutdown()方法。

shutdown()方法

當(dāng)使用線程池的時(shí)候,調(diào)用了shutdown()方法后,線程池就不會(huì)再接受新的執(zhí)行任務(wù)了。但是在調(diào)用shutdown()方法之前放入任務(wù)隊(duì)列中的任務(wù)還是要執(zhí)行的。此方法是非阻塞方法,調(diào)用后會(huì)立即返回,并不會(huì)等待任務(wù)隊(duì)列中的任務(wù)全部執(zhí)行完畢后再返回。我們看下shutdown()方法的源代碼,如下所示。

public void shutdown() {
	//獲取線程池的全局鎖
	final ReentrantLock mainLock = this.mainLock;
	mainLock.lock();
	try {
		//檢查是否有關(guān)閉線程池的權(quán)限
		checkShutdownAccess();
		//將當(dāng)前線程池的狀態(tài)設(shè)置為SHUTDOWN
		advanceRunState(SHUTDOWN);
		//中斷Worker線程
		interruptIdleWorkers();
		//為ScheduledThreadPoolExecutor調(diào)用鉤子函數(shù)
		onShutdown(); // hook for 
	} finally {
		//釋放線程池的全局鎖
		mainLock.unlock();
	}
	//嘗試將狀態(tài)變?yōu)門ERMINATED
	tryTerminate();
}

總體來說,shutdown()方法的代碼比較簡(jiǎn)單,首先檢查了是否有權(quán)限來關(guān)閉線程池,如果有權(quán)限,則再次檢測(cè)是否有中斷工作線程的權(quán)限,如果沒有權(quán)限,則會(huì)拋出SecurityException異常,代碼如下所示。

//檢查是否有關(guān)閉線程池的權(quán)限
checkShutdownAccess();
//將當(dāng)前線程池的狀態(tài)設(shè)置為SHUTDOWN
advanceRunState(SHUTDOWN);
//中斷Worker線程
interruptIdleWorkers();

其中,checkShutdownAccess()方法的實(shí)現(xiàn)代碼如下所示。

private void checkShutdownAccess() {
	SecurityManager security = System.getSecurityManager();
	if (security != null) {
		security.checkPermission(shutdownPerm);
		final ReentrantLock mainLock = this.mainLock;
		mainLock.lock();
		try {
			for (Worker w : workers)
				security.checkAccess(w.thread);
		} finally {
			mainLock.unlock();
		}
	}
}

對(duì)于checkShutdownAccess()方法的代碼理解起來比較簡(jiǎn)單,就是檢測(cè)是否具有關(guān)閉線程池的權(quán)限,期間使用了線程池的全局鎖。

接下來,我們看advanceRunState(int)方法的源代碼,如下所示。

private void advanceRunState(int targetState) {
	for (;;) {
		int c = ctl.get();
		if (runStateAtLeast(c, targetState) ||
			ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c))))
			break;
	}
}

advanceRunState(int)方法的整體邏輯就是:判斷當(dāng)前線程池的狀態(tài)是否為指定的狀態(tài),在shutdown()方法中傳遞的狀態(tài)是SHUTDOWN,如果是SHUTDOWN,則直接返回;如果不是SHUTDOWN,則將當(dāng)前線程池的狀態(tài)設(shè)置為SHUTDOWN。

接下來,我們看看showdown()方法調(diào)用的interruptIdleWorkers()方法,如下所示。

private void interruptIdleWorkers() {
	interruptIdleWorkers(false);
}

可以看到,interruptIdleWorkers()方法調(diào)用的是interruptIdleWorkers(boolean)方法,繼續(xù)看interruptIdleWorkers(boolean)方法的源代碼,如下所示。

private void interruptIdleWorkers(boolean onlyOne) {
	final ReentrantLock mainLock = this.mainLock;
	mainLock.lock();
	try {
		for (Worker w : workers) {
			Thread t = w.thread;
			if (!t.isInterrupted() && w.tryLock()) {
				try {
					t.interrupt();
				} catch (SecurityException ignore) {
				} finally {
					w.unlock();
				}
			}
			if (onlyOne)
				break;
		}
	} finally {
		mainLock.unlock();
	}
}

上述代碼的總體邏輯為:獲取線程池的全局鎖,循環(huán)所有的工作線程,檢測(cè)線程是否被中斷,如果沒有被中斷,并且Worker線程獲得了鎖,則執(zhí)行線程的中斷方法,并釋放線程獲取到的鎖。此時(shí)如果onlyOne參數(shù)為true,則退出循環(huán)。否則,循環(huán)所有的工作線程,執(zhí)行相同的操作。最終,釋放線程池的全局鎖。

接下來,我們看下shutdownNow()方法。

shutdownNow()方法

如果調(diào)用了線程池的shutdownNow()方法,則線程池不會(huì)再接受新的執(zhí)行任務(wù),也會(huì)將任務(wù)隊(duì)列中存在的任務(wù)丟棄,正在執(zhí)行的Worker線程也會(huì)被立即中斷,同時(shí),方法會(huì)立刻返回,此方法存在一個(gè)返回值,也就是當(dāng)前任務(wù)隊(duì)列中被丟棄的任務(wù)列表。

shutdownNow()方法的源代碼如下所示。

public List<Runnable> shutdownNow() {
	List<Runnable> tasks;
	final ReentrantLock mainLock = this.mainLock;
	mainLock.lock();
	try {
		//檢查是否有關(guān)閉權(quán)限
		checkShutdownAccess();
		//設(shè)置線程池的狀態(tài)為STOP
		advanceRunState(STOP);
		//中斷所有的Worker線程
		interruptWorkers();
		//將任務(wù)隊(duì)列中的任務(wù)移動(dòng)到tasks集合中
		tasks = drainQueue();
	} finally {
		mainLock.unlock();
	}
	/嘗試將狀態(tài)變?yōu)門ERMINATED
	tryTerminate();
	//返回tasks集合
	return tasks;
}

shutdownNow()方法的源代碼的總體邏輯與shutdown()方法基本相同,只是shutdownNow()方法將線程池的狀態(tài)設(shè)置為STOP,中斷所有的Worker線程,并且將任務(wù)隊(duì)列中的所有任務(wù)移動(dòng)到tasks集合中并返回。

可以看到,shutdownNow()方法中斷所有的線程時(shí),調(diào)用了interruptWorkers()方法,接下來,我們就看下interruptWorkers()方法的源代碼,如下所示。

private void interruptWorkers() {
	final ReentrantLock mainLock = this.mainLock;
	mainLock.lock();
	try {
		for (Worker w : workers)
			w.interruptIfStarted();
	} finally {
		mainLock.unlock();
	}
}

interruptWorkers()方法的邏輯比較簡(jiǎn)單,就是獲得線程池的全局鎖,循環(huán)所有的工作線程,依次中斷線程,最后釋放線程池的全局鎖。

在interruptWorkers()方法的內(nèi)部,實(shí)際上調(diào)用的是Worker類的interruptIfStarted()方法來中斷線程,我們看下Worker類的interruptIfStarted()方法的源代碼,如下所示。

void interruptIfStarted() {
	Thread t;
	if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
		try {
			t.interrupt();
		} catch (SecurityException ignore) {
		}
	}
}

發(fā)現(xiàn)其本質(zhì)上調(diào)用的還是Thread類的interrupt()方法來中斷線程。

awaitTermination(long, TimeUnit)方法

當(dāng)線程池調(diào)用了awaitTermination(long, TimeUnit)方法后,會(huì)阻塞調(diào)用者所在的線程,直到線程池的狀態(tài)修改為TERMINATED才返回,或者達(dá)到了超時(shí)時(shí)間返回。接下來,我們看下awaitTermination(long, TimeUnit)方法的源代碼,如下所示。

public boolean awaitTermination(long timeout, TimeUnit unit)
	throws InterruptedException {
	//獲取距離超時(shí)時(shí)間剩余的時(shí)長(zhǎng)
	long nanos = unit.toNanos(timeout);
	//獲取Worker線程的的全局鎖
	final ReentrantLock mainLock = this.mainLock;
	//加鎖
	mainLock.lock();
	try {
		for (;;) {
			//當(dāng)前線程池狀態(tài)為TERMINATED狀態(tài),會(huì)返回true
			if (runStateAtLeast(ctl.get(), TERMINATED))
				return true;
			//達(dá)到超時(shí)時(shí)間,已超時(shí),則返回false
			if (nanos <= 0)
				return false;
			//重置距離超時(shí)時(shí)間的剩余時(shí)長(zhǎng)
			nanos = termination.awaitNanos(nanos);
		}
	} finally {
		//釋放鎖
		mainLock.unlock();
	}
}

上述代碼的總體邏輯為:首先獲取Worker線程的獨(dú)占鎖,后在循環(huán)判斷當(dāng)前線程池是否已經(jīng)是TERMINATED狀態(tài),如果是則直接返回true,否則檢測(cè)是否已經(jīng)超時(shí),如果已經(jīng)超時(shí),則返回false。如果未超時(shí),則重置距離超時(shí)時(shí)間的剩余時(shí)長(zhǎng)。接下來,進(jìn)入下一輪循環(huán),再次檢測(cè)當(dāng)前線程池是否已經(jīng)是TERMINATED狀態(tài),如果是則直接返回true,否則檢測(cè)是否已經(jīng)超時(shí),如果已經(jīng)超時(shí),則返回false。如果未超時(shí),則重置距離超時(shí)時(shí)間的剩余時(shí)長(zhǎng)。以此循環(huán),直到線程池的狀態(tài)變?yōu)門ERMINATED或者已經(jīng)超時(shí)。

到此這篇關(guān)于詳解Java線程池如何實(shí)現(xiàn)優(yōu)雅退出的文章就介紹到這了,更多相關(guān)Java線程池退出內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • MyBatis不同Mapper文件引用resultMap實(shí)例代碼

    MyBatis不同Mapper文件引用resultMap實(shí)例代碼

    這篇文章主要介紹了mybatis 不同Mapper文件引用resultMap的實(shí)例代碼,非常不錯(cuò)具有參考借鑒價(jià)值,需要的朋友可以參考下
    2017-07-07
  • Mybatis-Plus或PageHelper多表分頁(yè)查詢總條數(shù)不對(duì)問題的解決方法

    Mybatis-Plus或PageHelper多表分頁(yè)查詢總條數(shù)不對(duì)問題的解決方法

    PageHelper 這個(gè)插件用了很多次了,今天使用的時(shí)候才遇到一個(gè)問題,這篇文章主要給大家介紹了關(guān)于Mybatis-Plus或PageHelper多表分頁(yè)查詢總條數(shù)不對(duì)問題的解決方法,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-08-08
  • 使用Homebrew配置Java開發(fā)環(huán)境操作方法

    使用Homebrew配置Java開發(fā)環(huán)境操作方法

    下面小編就為大家?guī)硪黄褂肏omebrew配置Java開發(fā)環(huán)境操作方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-06-06
  • SpringBoot用多線程批量導(dǎo)入數(shù)據(jù)庫(kù)實(shí)現(xiàn)方法

    SpringBoot用多線程批量導(dǎo)入數(shù)據(jù)庫(kù)實(shí)現(xiàn)方法

    這篇文章主要介紹了SpringBoot用多線程批量導(dǎo)入數(shù)據(jù)庫(kù)實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2023-02-02
  • 淺談java8中map的新方法--replace

    淺談java8中map的新方法--replace

    下面小編就為大家?guī)硪黄獪\談java8中map的新方法--replace。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2016-10-10
  • SpringMVC @ResponseBody 415錯(cuò)誤處理方式

    SpringMVC @ResponseBody 415錯(cuò)誤處理方式

    這篇文章主要介紹了SpringMVC @ResponseBody 415錯(cuò)誤處理方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • java實(shí)現(xiàn)讀取jar包中配置文件的幾種方式

    java實(shí)現(xiàn)讀取jar包中配置文件的幾種方式

    本文主要介紹了java實(shí)現(xiàn)讀取jar包中配置文件的幾種方式,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06
  • 關(guān)于java String中intern的深入講解

    關(guān)于java String中intern的深入講解

    這篇文章主要給大家介紹了關(guān)于java String中intern的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用java具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • 最大子數(shù)組和Java實(shí)現(xiàn)代碼示例

    最大子數(shù)組和Java實(shí)現(xiàn)代碼示例

    這篇文章主要介紹了最大子數(shù)組和Java實(shí)現(xiàn)的相關(guān)資料,文中介紹了兩種方法來解決尋找具有最大和的連續(xù)子數(shù)組的問題,第一種方法是動(dòng)態(tài)規(guī)劃,第二種方法是分治法,需要的朋友可以參考下
    2024-11-11
  • Java編程訪問權(quán)限的控制代碼詳解

    Java編程訪問權(quán)限的控制代碼詳解

    這篇文章主要介紹了Java編程訪問權(quán)限的控制代碼詳解,涉及包名,公共的和私有的等相關(guān)內(nèi)容,分享了相關(guān)代碼示例,小編覺得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下
    2018-01-01

最新評(píng)論

大庆市| 茶陵县| 桃源县| 南康市| 五台县| 安宁市| 称多县| 苏州市| 绵阳市| 盖州市| 伊春市| 鄂伦春自治旗| 台北县| 班玛县| 崇明县| 渝北区| 神木县| 石河子市| 台安县| 庆阳市| 阿坝| 田阳县| 莱芜市| 浦北县| 烟台市| 德江县| 益阳市| 三河市| 伊金霍洛旗| 福泉市| 康保县| 界首市| 乐亭县| 周宁县| 蚌埠市| 定安县| 房产| 岳阳市| 清远市| 石家庄市| 于都县|