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

java線程池中Worker線程執(zhí)行流程原理解析

 更新時間:2022年11月25日 15:51:27   作者:冰_河  
這篇文章主要為大家介紹了java線程池中Worker線程執(zhí)行流程原理解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

引言

在《【高并發(fā)】別鬧了,這樣理解線程池執(zhí)行任務的核心流程才正確?。?/a>》一文中我們深度分析了線程池執(zhí)行任務的核心流程,在ThreadPoolExecutor類的addWorker(Runnable, boolean)方法中,使用CAS安全的更新線程的數(shù)量之后,接下來就是創(chuàng)建新的Worker線程執(zhí)行任務,所以,我們先來分析下Worker類的源碼。

Worker類分析

Worker類從類的結(jié)構(gòu)上來看,繼承了AQS(AbstractQueuedSynchronizer類)并實現(xiàn)了Runnable接口。本質(zhì)上,Worker類既是一個同步組件,也是一個執(zhí)行任務的線程。

接下來,我們看下Worker類的源碼,如下所示。

private final class Worker extends AbstractQueuedSynchronizer implements Runnable {
	private static final long serialVersionUID = 6138294804551838833L;
	//執(zhí)行任務的線程類
	final Thread thread;
	//初始化執(zhí)行的任務,第一次執(zhí)行的任務
	Runnable firstTask;
	//完成任務的計數(shù)
	volatile long completedTasks;
	//Worker類的構(gòu)造方法,初始化任務并調(diào)用線程工廠創(chuàng)建執(zhí)行任務的線程
	Worker(Runnable firstTask) {
		setState(-1); 
		this.firstTask = firstTask;
		this.thread = getThreadFactory().newThread(this);
	}
	//重寫Runnable接口的run()方法
	public void run() {
		//調(diào)用ThreadPoolExecutor類的runWorker(Worker)方法
		runWorker(this);
	}
	//檢測是否是否獲取到鎖
	//state=0表示未獲取到鎖
	//state=1表示已獲取到鎖
	protected boolean isHeldExclusively() {
		return getState() != 0;
	}
	//使用AQS設置線程狀態(tài)
	protected boolean tryAcquire(int unused) {
		if (compareAndSetState(0, 1)) {
			setExclusiveOwnerThread(Thread.currentThread());
			return true;
		}
		return false;
	}
	//嘗試釋放鎖
	protected boolean tryRelease(int unused) {
		setExclusiveOwnerThread(null);
		setState(0);
		return true;
	}
	public void lock()        { acquire(1); }
	public boolean tryLock()  { return tryAcquire(1); }
	public void unlock()      { release(1); }
	public boolean isLocked() { return isHeldExclusively(); }
	void interruptIfStarted() {
		Thread t;
		if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
			try {
				t.interrupt();
			} catch (SecurityException ignore) {
			}
		}
	}
}

在Worker類的構(gòu)造方法中,可以看出,首先將同步狀態(tài)state設置為-1,設置為-1是為了防止runWorker方法運行之前被中斷。這是因為如果其他線程調(diào)用線程池的shutdownNow()方法時,如果Worker類中的state狀態(tài)的值大于0,則會中斷線程,如果state狀態(tài)的值為-1,則不會中斷線程。

Worker類實現(xiàn)了Runnable接口,需要重寫run方法,而Worker的run方法本質(zhì)上調(diào)用的是ThreadPoolExecutor類的runWorker方法,在runWorker方法中,會首先調(diào)用unlock方法,該方法會將state置為0,所以這個時候調(diào)用shutDownNow方法就會中斷當前線程,而這個時候已經(jīng)進入了runWork方法,就不會在還沒有執(zhí)行runWorker方法的時候就中斷線程。

注意:大家需要重點理解Worker類的實現(xiàn)。

Worker類中調(diào)用了ThreadPoolExecutor類的runWorker(Worker)方法。接下來,我們一起看下ThreadPoolExecutor類的runWorker(Worker)方法的實現(xiàn)。

runWorker(Worker)方法

首先,我們看下RunWorker(Worker)方法的源碼,如下所示。

final void runWorker(Worker w) {
	Thread wt = Thread.currentThread();
	Runnable task = w.firstTask;
	w.firstTask = null;
	//釋放鎖,將state設置為0,允許中斷任務的執(zhí)行
	w.unlock();
	boolean completedAbruptly = true;
	try {
		//如果任務不為空,或者從任務隊列中獲取的任務不為空,則執(zhí)行while循環(huán)
		while (task != null || (task = getTask()) != null) {
			//如果任務不為空,則獲取Worker工作線程的獨占鎖
			w.lock();
			//如果線程已經(jīng)停止,或者中斷線程后線程終止并且沒有成功中斷線程
			//大家好好理解下這個邏輯
			if ((runStateAtLeast(ctl.get(), STOP) ||
				 (Thread.interrupted() &&
				  runStateAtLeast(ctl.get(), STOP))) &&
				!wt.isInterrupted())
				//中斷線程
				wt.interrupt();
			try {
				//執(zhí)行任務前執(zhí)行的邏輯
				beforeExecute(wt, task);
				Throwable thrown = null;
				try {
					//調(diào)用Runable接口的run方法執(zhí)行任務
					task.run();
				} catch (RuntimeException x) {
					thrown = x; throw x;
				} catch (Error x) {
					thrown = x; throw x;
				} catch (Throwable x) {
					thrown = x; throw new Error(x);
				} finally {
					//執(zhí)行任務后執(zhí)行的邏輯
					afterExecute(task, thrown);
				}
			} finally {
				//任務執(zhí)行完成后,將其設置為空
				task = null;
				//完成的任務數(shù)量加1
				w.completedTasks++;
				//釋放工作線程獲得的鎖
				w.unlock();
			}
		}
		completedAbruptly = false;
	} finally {
		//執(zhí)行退出Worker線程的邏輯
		processWorkerExit(w, completedAbruptly);
	}
}

這里,我們拆解runWorker(Worker)方法。

(1)獲取當前線程的句柄和工作線程中的任務,并將工作線程中的任務設置為空,執(zhí)行unlock方法釋放鎖,將state狀態(tài)設置為0,此時可以中斷工作線程,代碼如下所示。

Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
//釋放鎖,將state設置為0,允許中斷任務的執(zhí)行
w.unlock();

(2)在while循環(huán)中進行判斷,如果任務不為空,或者從任務隊列中獲取的任務不為空,則執(zhí)行while循環(huán),否則,調(diào)用processWorkerExit(Worker, boolean)方法退出Worker工作線程。

while (task != null || (task = getTask()) != null)

(3)如果滿足while的循環(huán)條件,首先獲取工作線程內(nèi)部的獨占鎖,并執(zhí)行一系列的邏輯判斷來檢測是否需要中斷當前線程的執(zhí)行,代碼如下所示。

//如果任務不為空,則獲取Worker工作線程的獨占鎖
w.lock();
//如果線程已經(jīng)停止,或者中斷線程后線程終止并且沒有成功中斷線程
//大家好好理解下這個邏輯
if ((runStateAtLeast(ctl.get(), STOP) ||
	 (Thread.interrupted() &&
	  runStateAtLeast(ctl.get(), STOP))) &&
	!wt.isInterrupted())
	//中斷線程
	wt.interrupt();

(4)調(diào)用執(zhí)行任務前執(zhí)行的邏輯,如下所示

//執(zhí)行任務前執(zhí)行的邏輯
beforeExecute(wt, task);

(5)調(diào)用Runable接口的run方法執(zhí)行任務

//調(diào)用Runable接口的run方法執(zhí)行任務
task.run();

(6)調(diào)用執(zhí)行任務后執(zhí)行的邏輯

//執(zhí)行任務后執(zhí)行的邏輯
afterExecute(task, thrown);

(7)將完成的任務設置為空,完成的任務數(shù)量加1并釋放工作線程的鎖。

//任務執(zhí)行完成后,將其設置為空
task = null;
//完成的任務數(shù)量加1
w.completedTasks++;
//釋放工作線程獲得的鎖
w.unlock();

(8)退出Worker線程的執(zhí)行,如下所示

//執(zhí)行退出Worker線程的邏輯
processWorkerExit(w, completedAbruptly);

從代碼分析上可以看到,當從Worker線程中獲取的任務為空時,會調(diào)用getTask()方法從任務隊列中獲取任務,接下來,我們看下getTask()方法的實現(xiàn)。

getTask()方法

我們先來看下getTask()方法的源代碼,如下所示。

private Runnable getTask() {
	//輪詢是否超時的標識
	boolean timedOut = false;
	//自旋for循環(huán)
	for (;;) {
		//獲取ctl
		int c = ctl.get();
		//獲取線程池的狀態(tài)
		int rs = runStateOf(c);
		//檢測任務隊列是否在線程池停止或關閉的時候為空
		//也就是說任務隊列是否在線程池未正常運行時為空
		if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
			//減少Worker線程的數(shù)量
			decrementWorkerCount();
			return null;
		}
		//獲取線程池中線程的數(shù)量
		int wc = workerCountOf(c);
		//檢測當前線程池中的線程數(shù)量是否大于corePoolSize的值或者是否正在等待執(zhí)行任務
		boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
		//如果線程池中的線程數(shù)量大于corePoolSize
		//獲取大于corePoolSize或者是否正在等待執(zhí)行任務并且輪詢超時
		//并且當前線程池中的線程數(shù)量大于1或者任務隊列為空
		if ((wc > maximumPoolSize || (timed && timedOut))
			&& (wc > 1 || workQueue.isEmpty())) {
			//成功減少線程池中的工作線程數(shù)量
			if (compareAndDecrementWorkerCount(c))
				return null;
			continue;
		}
		try {
			//從任務隊列中獲取任務
			Runnable r = timed ?
				workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
				workQueue.take();
			//任務不為空直接返回任務
			if (r != null)
				return r;
			timedOut = true;
		} catch (InterruptedException retry) {
			timedOut = false;
		}
	}
}

getTask()方法的邏輯比較簡單,大家看源碼就可以了,我這里就不重復描述了。

接下來,我們看下在正式調(diào)用Runnable的run()方法前后,執(zhí)行的beforeExecute方法和afterExecute方法。

beforeExecute(Thread, Runnable)方法

beforeExecute(Thread, Runnable)方法的源代碼如下所示。

protected void beforeExecute(Thread t, Runnable r) { }

可以看到,beforeExecute(Thread, Runnable)方法的方法體為空,我們可以創(chuàng)建ThreadPoolExecutor的子類來重寫beforeExecute(Thread, Runnable)方法,使得線程池正式執(zhí)行任務之前,執(zhí)行我們自己定義的業(yè)務邏輯。

afterExecute(Runnable, Throwable)方法

afterExecute(Runnable, Throwable)方法的源代碼如下所示。

protected void afterExecute(Runnable r, Throwable t) { }

可以看到,afterExecute(Runnable, Throwable)方法的方法體同樣為空,我們可以創(chuàng)建ThreadPoolExecutor的子類來重寫afterExecute(Runnable, Throwable)方法,使得線程池在執(zhí)行任務之后執(zhí)行我們自己定義的業(yè)務邏輯。

接下來,就是退出工作線程的processWorkerExit(Worker, boolean)方法。

processWorkerExit(Worker, boolean)方法

processWorkerExit(Worker, boolean)方法的邏輯主要是執(zhí)行退出Worker線程,并且對一些資源進行清理,源代碼如下所示。

private void processWorkerExit(Worker w, boolean completedAbruptly) {
	//執(zhí)行過程中出現(xiàn)了異常,突然中斷
	if (completedAbruptly)
		//將工作線程的數(shù)量減1
		decrementWorkerCount();
	//獲取全局鎖
	final ReentrantLock mainLock = this.mainLock;
	mainLock.lock();
	try {
		//累加完成的任務數(shù)量
		completedTaskCount += w.completedTasks;
		//將完成的任務從workers集合中移除
		workers.remove(w);
	} finally {
		//釋放鎖
		mainLock.unlock();
	}
	//嘗試終止工作線程的執(zhí)行
	tryTerminate();
	//獲取ctl
	int c = ctl.get();
	//判斷當前線程池的狀態(tài)是否小于STOP(RUNNING或者SHUTDOWN)
	if (runStateLessThan(c, STOP)) {
		//如果沒有突然中斷完成
		if (!completedAbruptly) {
			//如果allowCoreThreadTimeOut為true,為min賦值為0,否則賦值為corePoolSize
			int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
			//如果min為0并且工作隊列不為空
			if (min == 0 && ! workQueue.isEmpty())
				//min的值設置為1
				min = 1;
			//如果線程池中的線程數(shù)量大于min的值
			if (workerCountOf(c) >= min)
				//返回,不再執(zhí)行程序
				return; 
		}
		//調(diào)用addWorker方法
		addWorker(null, false);
	}
}

接下來,我們拆解processWorkerExit(Worker, boolean)方法。

(1)執(zhí)行過程中出現(xiàn)了異常,突然中斷執(zhí)行,則將工作線程數(shù)量減1,如下所示。

//執(zhí)行過程中出現(xiàn)了異常,突然中斷
if (completedAbruptly)
	//將工作線程的數(shù)量減1
	decrementWorkerCount();

(2)獲取鎖累加完成的任務數(shù)量,并將完成的任務從workers集合中移除,并釋放,如下所示。

//獲取全局鎖
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
	//累加完成的任務數(shù)量
	completedTaskCount += w.completedTasks;
	//將完成的任務從workers集合中移除
	workers.remove(w);
} finally {
	//釋放鎖
	mainLock.unlock();
}

(3)嘗試終止工作線程的執(zhí)行

//嘗試終止工作線程的執(zhí)行
tryTerminate();

(4)處判斷當前線程池中的線程個數(shù)是否小于核心線程數(shù),如果是,需要新增一個線程保證有足夠的線程可以執(zhí)行任務隊列中的任務或者提交的任務。

//獲取ctl
int c = ctl.get();
//判斷當前線程池的狀態(tài)是否小于STOP(RUNNING或者SHUTDOWN)
if (runStateLessThan(c, STOP)) {
	//如果沒有突然中斷完成
	if (!completedAbruptly) {
		//如果allowCoreThreadTimeOut為true,為min賦值為0,否則賦值為corePoolSize
		int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
		//如果min為0并且工作隊列不為空
		if (min == 0 && ! workQueue.isEmpty())
			//min的值設置為1
			min = 1;
		//如果線程池中的線程數(shù)量大于min的值
		if (workerCountOf(c) >= min)
			//返回,不再執(zhí)行程序
			return; 
	}
	//調(diào)用addWorker方法
	addWorker(null, false);
}

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

tryTerminate()方法

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

final void tryTerminate() {
	//自旋for循環(huán)
	for (;;) {
		//獲取ctl
		int c = ctl.get();
		//如果線程池的狀態(tài)為RUNNING
		//或者狀態(tài)大于TIDYING
		//或者狀態(tài)為SHUTDOWN并且任務隊列為空
		//直接返回程序,不再執(zhí)行后續(xù)邏輯
		if (isRunning(c) ||
			runStateAtLeast(c, TIDYING) ||
			(runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
			return;
		//如果當前線程池中的線程數(shù)量不等于0
		if (workerCountOf(c) != 0) { 
			//中斷線程的執(zhí)行
			interruptIdleWorkers(ONLY_ONE);
			return;
		}
		//獲取線程池的全局鎖
		final ReentrantLock mainLock = this.mainLock;
		mainLock.lock();
		try {
			//通過CAS將線程池的狀態(tài)設置為TIDYING
			if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
				try {
					//調(diào)用terminated()方法
					terminated();
				} finally {
					//將線程池狀態(tài)設置為TERMINATED
					ctl.set(ctlOf(TERMINATED, 0));
					//喚醒所有因為調(diào)用線程池的awaitTermination方法而被阻塞的線程
					termination.signalAll();
				}
				return;
			}
		} finally {
			//釋放鎖
			mainLock.unlock();
		}
	}
}

(1)獲取ctl,根據(jù)情況設置線程池狀態(tài)或者中斷線程的執(zhí)行,并返回。

//獲取ctl
int c = ctl.get();
//如果線程池的狀態(tài)為RUNNING
//或者狀態(tài)大于TIDYING
//或者狀態(tài)為SHUTDOWN并且任務隊列為空
//直接返回程序,不再執(zhí)行后續(xù)邏輯
if (isRunning(c) ||
	runStateAtLeast(c, TIDYING) ||
	(runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
	return;
//如果當前線程池中的線程數(shù)量不等于0
if (workerCountOf(c) != 0) { 
	//中斷線程的執(zhí)行
	interruptIdleWorkers(ONLY_ONE);
	return;
}

(2)獲取全局鎖,通過CAS設置線程池的狀態(tài),調(diào)用terminated()方法執(zhí)行邏輯,最終將線程池的狀態(tài)設置為TERMINATED,喚醒所有因為調(diào)用線程池的awaitTermination方法而被阻塞的線程,最終釋放鎖,如下所示。

//獲取線程池的全局
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
	//通過CAS將線程池的狀態(tài)設置為TIDYING
	if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
		try {
			//調(diào)用terminated()方法
			terminated();
		} finally {
			//將線程池狀態(tài)設置為TERMINATED
			ctl.set(ctlOf(TERMINATED, 0));
			//喚醒所有因為調(diào)用線程池的awaitTermination方法而被阻塞的線程
			termination.signalAll();
		}
		return;
	}
} finally {
	//釋放鎖
	mainLock.unlock();
}

接下來,看下terminated()方法。

terminated()方法

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

protected void terminated() { }

可以看到,terminated()方法的方法體為空,我們可以創(chuàng)建ThreadPoolExecutor的子類來重寫terminated()方法,值得Worker線程調(diào)用tryTerminate()方法時執(zhí)行我們自己定義的terminated()方法的業(yè)務邏輯。

以上就是java線程池中Worker線程執(zhí)行流程原理解析的詳細內(nèi)容,更多關于java線程池Worker線程執(zhí)行的資料請關注腳本之家其它相關文章!

相關文章

  • Java用list儲存,遍歷,查詢指定信息過程詳解

    Java用list儲存,遍歷,查詢指定信息過程詳解

    這篇文章主要介紹了Java用list儲存,遍歷,查詢指定信息過程詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-10-10
  • Spring?Data?JPA命名約定查詢實現(xiàn)方法

    Spring?Data?JPA命名約定查詢實現(xiàn)方法

    這篇文章主要為大家介紹了Spring?Data?JPA命名約定查詢實現(xiàn)方法示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-12-12
  • 一文搞懂Spring中的注解與反射

    一文搞懂Spring中的注解與反射

    這篇文章主要為大家介紹了Spring中的注解與反射的原理與實現(xiàn),文中的示例代碼講解詳細,對我們了解Spring有一定的幫助,需要的可以參考一下
    2022-06-06
  • RestTemplate如何添加請求頭headers和請求體body

    RestTemplate如何添加請求頭headers和請求體body

    這篇文章主要介紹了RestTemplate如何添加請求頭headers和請求體body問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • Springboot項目的搭建教程(分離出common父依賴)

    Springboot項目的搭建教程(分離出common父依賴)

    這篇文章主要介紹了Springboot項目的搭建教程(分離出common父依賴),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • 基于SpringBoot和Vue3的博客平臺文章詳情與評論功能實現(xiàn)

    基于SpringBoot和Vue3的博客平臺文章詳情與評論功能實現(xiàn)

    在前面的教程中,我們已經(jīng)實現(xiàn)了基于Spring Boot和Vue3的發(fā)布、編輯、刪除文章功能以及文章列表與分頁功能。本教程將引導您實現(xiàn)博客平臺的文章詳情與評論功能,需要的朋友可以參考一下
    2023-04-04
  • 詳解SpringBoot如何讓指定的Bean先加載

    詳解SpringBoot如何讓指定的Bean先加載

    這篇文章主要給大家介紹了在 SpringBoot 中如何讓自己的某個指定的 Bean 在其他 Bean 前完成被 Spring 加載,文中通過代碼示例給大家講解的非常詳細,對大家的學習或工作有一定的幫助,需要的朋友可以參考下
    2024-06-06
  • SpringBoot中集成screw(螺絲釘)實現(xiàn)數(shù)據(jù)庫表結(jié)構(gòu)文檔生成方法

    SpringBoot中集成screw(螺絲釘)實現(xiàn)數(shù)據(jù)庫表結(jié)構(gòu)文檔生成方法

    這篇文章主要介紹了SpringBoot中集成screw(螺絲釘)實現(xiàn)數(shù)據(jù)庫表結(jié)構(gòu)文檔生成,下面以連接mysql數(shù)據(jù)庫并生成html格式的數(shù)據(jù)庫結(jié)構(gòu)文檔為例,插件的使用方式除可以使用代碼外,還可以使用Maven插件的方式,需要的朋友可以參考下
    2024-07-07
  • 解決idea無法導入識別本地類的問題

    解決idea無法導入識別本地類的問題

    今天做實驗不知道按了哪里不能導入識別本地的類,只有jar包的類,百度搜索也沒有找到合理的解決方案,經(jīng)過朋友援助問題根源找到,下面小編把解決方法分享給大家,需要的朋友參考下吧
    2021-08-08
  • Java 垃圾回收機制詳解(動力節(jié)點Java學院整理)

    Java 垃圾回收機制詳解(動力節(jié)點Java學院整理)

    在系統(tǒng)運行過程中,會產(chǎn)生一些無用的對象,這些對象占據(jù)著一定的內(nèi)存,如果不對這些對象清理回收無用對象的內(nèi)存,可能會導致內(nèi)存的耗盡,所以垃圾回收機制回收的是內(nèi)存。下面通過本文給大家詳細介紹java垃圾回收機制,一起學習吧
    2017-02-02

最新評論

诸城市| 青田县| 西丰县| 泗水县| 崇左市| 贵州省| 津市市| 桐城市| 潞城市| 沾益县| 梁山县| 专栏| 北宁市| 台湾省| 永州市| 仪征市| 隆子县| 肥西县| 威信县| 灌南县| 共和县| 曲靖市| 彭泽县| 峨眉山市| 吴川市| 化德县| 花莲县| 陆良县| 兴隆县| 天等县| 鄯善县| 黑河市| 菏泽市| 山西省| 全椒县| 广水市| 措美县| 北辰区| 额尔古纳市| 章丘市| 高密市|