搜尋
首頁Javajava教程Java線程池如何優雅地實現關閉?

shutdown()方法

當使用執行緒池的時候,呼叫了shutdown()方法後,執行緒池就不會再接受新的執行任務了。但是在呼叫shutdown()方法之前放入任務佇列中的任務還是要執行的。此方法是非阻塞方法,呼叫後會立即返回,並不會等待任務佇列中的任務全部執行完畢後再返回。我們看下shutdown()方法的原始碼,如下所示。

public void shutdown() {
	//获取线程池的全局锁
	final ReentrantLock mainLock = this.mainLock;
	mainLock.lock();
	try {
		//检查是否有关闭线程池的权限
		checkShutdownAccess();
		//将当前线程池的状态设置为SHUTDOWN
		advanceRunState(SHUTDOWN);
		//中断Worker线程
		interruptIdleWorkers();
		//为ScheduledThreadPoolExecutor调用钩子函数
		onShutdown(); // hook for 
	} finally {
		//释放线程池的全局锁
		mainLock.unlock();
	}
	//尝试将状态变为TERMINATED
	tryTerminate();
}

總體來說,shutdown()方法的程式碼比較簡單,首先檢查了是否有權限來關閉執行緒池,如果有權限,則再次偵測是否有中斷工作執行緒的權限,如果沒有權限,則會拋出SecurityException異常,程式碼如下所示。

//检查是否有关闭线程池的权限
checkShutdownAccess();
//将当前线程池的状态设置为SHUTDOWN
advanceRunState(SHUTDOWN);
//中断Worker线程
interruptIdleWorkers();

其中,checkShutdownAccess()方法的實作程式碼如下所示。

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();
		}
	}
}

對於checkShutdownAccess()方法的程式碼理解起來比較簡單,就是偵測是否具有關閉執行緒池的權限,期間使用了執行緒池的全域鎖定。

接下來,我們來看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)方法的整體邏輯是:判斷目前執行緒池的狀態是否為指定的狀態,在shutdown()方法中傳遞的狀態是SHUTDOWN,如果是SHUTDOWN,則直接傳回;如果不是SHUTDOWN,則將目前執行緒池的狀態設為SHUTDOWN。

接下來,我們來看看showdown()方法呼叫的interruptIdleWorkers()方法,如下所示。

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

可以看到,interruptIdleWorkers()方法呼叫的是interruptIdleWorkers(boolean)方法,繼續看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();
	}
}

上述程式碼的總體邏輯為:取得線程池的全域鎖,循環所有的工作線程,檢測線程是否被中斷,如果沒有中斷,並且Worker線程獲得了鎖,則執行線程的中斷方法,並釋放線程獲取到的鎖。此時如果onlyOne參數為true,則退出循環。否則,循環所有的工作線程,執行相同的操作。最終,釋放線程池的全域鎖定。

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

shutdownNow()方法

如果呼叫了執行緒池的shutdownNow()方法,則執行緒池不會再接受新的執行任務,也會將任務佇列中存在的任務丟棄,正在執行的Worker執行緒也會立即中斷,同時,方法會立刻傳回,此方法存在一個回傳值,也就是目前任務佇列中被丟棄的任務清單。

shutdownNow()方法的原始碼如下所示。

public List<Runnable> shutdownNow() {
	List<Runnable> tasks;
	final ReentrantLock mainLock = this.mainLock;
	mainLock.lock();
	try {
		//检查是否有关闭权限
		checkShutdownAccess();
		//设置线程池的状态为STOP
		advanceRunState(STOP);
		//中断所有的Worker线程
		interruptWorkers();
		//将任务队列中的任务移动到tasks集合中
		tasks = drainQueue();
	} finally {
		mainLock.unlock();
	}
	/尝试将状态变为TERMINATED
	tryTerminate();
	//返回tasks集合
	return tasks;
}

shutdownNow()方法的原始程式碼的總體邏輯基本上與shutdown()方法基本上相同,只是shutdownNow()方法將線程池的狀態設為STOP,中斷所有的Worker線程,並且將任務佇列中的所有任務移動到tasks集合中並返回。

可以看到,shutdownNow()方法中斷所有的執行緒時,呼叫了interruptWorkers()方法,接下來,我們就看下interruptWorkers()方法的原始碼,如下所示。

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

interruptWorkers()方法的邏輯比較簡單,就是取得線程池的全域鎖,循環所有的工作線程,依序中斷線程,最後釋放線程池的全域鎖定。

在interruptWorkers()方法的內部,實際上呼叫的是Worker類別的interruptIfStarted()方法來中斷線程,我們看下Worker類別的interruptIfStarted()方法的原始程式碼,如下所示。

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

發現其本質上呼叫的還是Thread類別的interrupt()方法來中斷執行緒。

awaitTermination(long, TimeUnit)方法

當線程池呼叫了awaitTermination(long, TimeUnit)方法後,會阻塞呼叫者所在的線程,直到線程池的狀態修改為TERMINATED才返回,或達到了超時時間返回。接下來,我們來看看awaitTermination(long, TimeUnit)方法的原始程式碼,如下所示。

public boolean awaitTermination(long timeout, TimeUnit unit)
	throws InterruptedException {
	//获取距离超时时间剩余的时长
	long nanos = unit.toNanos(timeout);
	//获取Worker线程的的全局锁
	final ReentrantLock mainLock = this.mainLock;
	//加锁
	mainLock.lock();
	try {
		for (;;) {
			//当前线程池状态为TERMINATED状态,会返回true
			if (runStateAtLeast(ctl.get(), TERMINATED))
				return true;
			//达到超时时间,已超时,则返回false
			if (nanos <= 0)
				return false;
			//重置距离超时时间的剩余时长
			nanos = termination.awaitNanos(nanos);
		}
	} finally {
		//释放锁
		mainLock.unlock();
	}
}

上述程式碼的整體邏輯為:先取得Worker執行緒的獨佔鎖,然後在迴圈判斷目前執行緒池是否已經是TERMINATED狀態,如果是則直接傳回true,否則偵測是否已經逾時,如果已經超時,則傳回false。如果未逾時,則重設距離逾時時間的剩餘時長。接下來,進入下一輪循環,再次偵測目前執行緒池是否已經是TERMINATED狀態,如果是則直接傳回true,否則偵測是否已經逾時,如果已經逾時,則傳回false。如果未逾時,則重設距離逾時時間的剩餘時長。以此循環,直到執行緒池的狀態變成TERMINATED或已經逾時。

以上是Java線程池如何優雅地實現關閉?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文轉載於:亿速云。如有侵權,請聯絡admin@php.cn刪除
JVM中的類加載程序子系統如何促進平台獨立性?JVM中的類加載程序子系統如何促進平台獨立性?Apr 23, 2025 am 12:14 AM

類加載器通過統一的類文件格式、動態加載、雙親委派模型和平台無關的字節碼,確保Java程序在不同平台上的一致性和兼容性,實現平台獨立性。

Java編譯器會產生特定於平台的代碼嗎?解釋。Java編譯器會產生特定於平台的代碼嗎?解釋。Apr 23, 2025 am 12:09 AM

Java編譯器生成的代碼是平台無關的,但最終執行的代碼是平台特定的。 1.Java源代碼編譯成平台無關的字節碼。 2.JVM將字節碼轉換為特定平台的機器碼,確保跨平台運行但性能可能不同。

JVM如何處理不同操作系統的多線程?JVM如何處理不同操作系統的多線程?Apr 23, 2025 am 12:07 AM

多線程在現代編程中重要,因為它能提高程序的響應性和資源利用率,並處理複雜的並發任務。 JVM通過線程映射、調度機制和同步鎖機制,在不同操作系統上確保多線程的一致性和高效性。

在Java的背景下,'平台獨立性”意味著什麼?在Java的背景下,'平台獨立性”意味著什麼?Apr 23, 2025 am 12:05 AM

Java的平台獨立性是指編寫的代碼可以在任何安裝了JVM的平台上運行,無需修改。 1)Java源代碼編譯成字節碼,2)字節碼由JVM解釋執行,3)JVM提供內存管理和垃圾回收功能,確保程序在不同操作系統上運行。

Java應用程序仍然可以遇到平台特定的錯誤或問題嗎?Java應用程序仍然可以遇到平台特定的錯誤或問題嗎?Apr 23, 2025 am 12:03 AM

Javaapplicationscanindeedencounterplatform-specificissuesdespitetheJVM'sabstraction.Reasonsinclude:1)Nativecodeandlibraries,2)Operatingsystemdifferences,3)JVMimplementationvariations,and4)Hardwaredependencies.Tomitigatethese,developersshould:1)Conduc

雲計算如何影響Java平台獨立性的重要性?雲計算如何影響Java平台獨立性的重要性?Apr 22, 2025 pm 07:05 PM

云计算显著提升了Java的平台独立性。1)Java代码编译为字节码,由JVM在不同操作系统上执行,确保跨平台运行。2)使用Docker和Kubernetes部署Java应用,提高可移植性和可扩展性。

Java的平台獨立性在廣泛採用中扮演著什麼角色?Java的平台獨立性在廣泛採用中扮演著什麼角色?Apr 22, 2025 pm 06:53 PM

Java'splatformindependenceallowsdeveloperstowritecodeonceandrunitonanydeviceorOSwithaJVM.Thisisachievedthroughcompilingtobytecode,whichtheJVMinterpretsorcompilesatruntime.ThisfeaturehassignificantlyboostedJava'sadoptionduetocross-platformdeployment,s

容器化技術(例如Docker)如何影響Java平台獨立性的重要性?容器化技術(例如Docker)如何影響Java平台獨立性的重要性?Apr 22, 2025 pm 06:49 PM

容器化技術如Docker增強而非替代Java的平台獨立性。 1)確保跨環境的一致性,2)管理依賴性,包括特定JVM版本,3)簡化部署過程,使Java應用更具適應性和易管理性。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

將Eclipse與SAP NetWeaver應用伺服器整合。

MantisBT

MantisBT

Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

Atom編輯器mac版下載

Atom編輯器mac版下載

最受歡迎的的開源編輯器

Dreamweaver Mac版

Dreamweaver Mac版

視覺化網頁開發工具

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版