ThreadPoolExecutor原始碼分析

2021-10-14 14:20:43 字數 4592 閱讀 6879

執行緒池的狀態

只有了解執行緒池的幾個狀態,才能讀懂它的核心原始碼。所以先說說這幾個狀態

running:為執行緒池初始化時的預設狀態,此狀態會接收任務進行處理

shutdown: 該狀態下的執行緒池不接收任何任務,但會等待正在執行的任務執行完。通常呼叫shutdown() 方法完成設定

stop: 該狀態的執行緒池不接收任何任務,同時不會等待正在執行的任務執行完畢。通常呼叫shutdownnow() 方法完成設定

tidying:該狀態下的執行緒池內,沒有任何執行緒和任務

terminated:該狀態為執行緒池的終態,通常呼叫tryterminate()方法完成設定

大多數情況下執行緒池的乙個生命週期流轉大概是running -> (shutdown,stop)-> tidying -> terminated

這幾個狀態在threadpoolexecutor原始碼中,通過乙個ctl的整型原子變數標識,高3位標識執行緒狀態,低29位標識執行緒數量。翻看原始碼就能看到

為執行緒池的核心方法,呼叫該方法任務就會執行,直接看下面**注釋吧

public void execute(runnable command) 

// 如果當前執行緒池的執行緒數量 > corepoolsize

// 且當前執行緒是否處於running ,則新增任務到佇列

if (isrunning(c) && workqueue.offer(command)) 

// 如果任務佇列滿,則新增worker物件,如果新增失敗執行拒絕策略

else if (!addworker(command, false))

reject(command);

}

以上為核心原始碼的分析,無非就是根據執行緒池情況新增worker、任務入隊、執行拒絕策略。可以看看下面這個流程圖,可能會更清晰

到這裡,我們可以來講講addworker 了。這個方法會封裝成乙個worker物件,然後執行任務。看看worker物件的類圖:

worker實現runnable介面、繼承abstractqueuedsynchronizer,持有乙個thread的成員變數。所以可以把worker物件看成乙個執行緒,同時擁有abstractqueuedsynchronizer的屬性和方法,因此它能夠進行加鎖和釋放鎖的操作。

ok,逐步跟進來看看addworker方法裡面的邏輯。

private boolean addworker(runnable firsttask, boolean core) 

}boolean workerstarted = false;

boolean workeradded = false;

worker w = null;

try 

} finally 

if (workeradded) 

}} finally 

return workerstarted;

}

整體還不算複雜,核心就是根據傳入的任務建立乙個worker物件,然後啟動worker。

下面來看看worker啟動的邏輯,前面說過了worker實現runnable介面,所以啟動將會觸發執行run方法,而run方法最終調的是runworker()方法。

final void runworker(worker w)  catch (runtimeexception x)  catch (error x)  catch (throwable x)  finally 

} finally 

}completedabruptly = false;

} finally 

}

整個方法的邏輯其實也不算複雜,就是當前worker不斷死迴圈獲取佇列裡面是否有任務。有,就加鎖然後執行任務。無,就阻塞等待獲取任務。那什麼情況下才會跳出整個死迴圈,執行processworkerexit呢?這裡就需要看下gettask() 方法邏輯了。

private runnable gettask() 

int wc = workercountof(c);

// 超時時間的標識,[是否設定了核心執行緒數的超時時間 或者 當前執行緒數量是否大於核心執行緒數 ],

//因為我們知道執行緒池執行的執行緒數量如果大於核心執行緒數,多出來的那部分執行緒是需要被**的。

boolean timed = allowcorethreadtimeout || wc > corepoolsize;

if ((wc > maximumpoolsize || (timed && timedout))

&& (wc > 1 || workqueue.isempty())) 

try  catch (interruptedexception retry) }}

最後,來看下processworkerexit() 方法處理了哪些邏輯

private void processworkerexit(worker w, boolean completedabruptly)  finally 

//嘗試將執行緒池狀態設定為 terminate

tryterminate();

//主要判斷當前執行緒池的執行緒數是否小於corepoolsize,如果小於繼續新增worker物件

int c = ctl.get();

if (runstatelessthan(c, stop)) 

addworker(null, false);}}

這個方法主要就是移除worker物件,然後嘗試將執行緒池的狀態更改為terminate。這裡需要講一下tryterminate方法邏輯,因為它和執行緒池awaittermination()方法有一定的關聯,來看看它的**。

final void tryterminate() 

final reentrantlock mainlock = this.mainlock;

//獲取mainlock鎖

mainlock.lock();

try  finally 

return;

}} finally }}

到這裡,執行緒池execute方法大致的邏輯就完了。可以再看看時序圖,理清下幾個方法和類之間的呼叫。中斷執行緒池的執行緒,會等待正在執行的執行緒結束執行,來看看原始碼它是怎麼實現的

public void shutdown()  finally 

//execute方法,我們分析過了,主要就是嘗試將執行緒池的狀態設定為terminate

tryterminate();

}

該方法我們比較關注的點是 interruptidleworkers方法,是怎樣中斷空閒worker,然後是如何保證worker執行完畢的?看看**就知道了

private void interruptidleworkers(boolean onlyone)  catch (securityexception ignore)  finally 

}if (onlyone)

break;

}} finally 

}

到這裡,核心邏輯就是通過w這個鎖來完成的。

public listshutdownnow()  finally 

tryterminate();

return tasks;    private void interruptworkers()  finally }}

原始碼和shutdown差不多,只不過將執行緒池狀態設定為stop,然後呼叫interruptworkers 方法,看看worker方法。

private void interruptworkers()  finally 

}

**中並沒有獲取w鎖的邏輯,所以這個方法會直接中斷所有執行緒,並不會等待那些正在執行任務的worker把任務執行完。

呼叫awaittermination方法會一直阻塞等待執行緒池狀態變為 terminated 才返回 或者等待超時返回。來看看**就明白了

public boolean awaittermination(long timeout, timeunit unit)

throws interruptedexception 

} finally 

}

(1)處的**已經告訴了該方法什麼時候返回,就是mainlock鎖的termination條件變數被喚醒返回。在上面分析中termination條件變數被喚醒是在執行tryterminate()時完成的,因為內部呼叫termination.signalall()。而tryterminate() 方法被shutdown() 和shutdownnow() 呼叫過,所以如果要讓awaittermination 返回,呼叫這2個方法就行。

- end -

Cartographer原始碼篇 原始碼分析 1

在安裝編譯cartographer 1.0.0的時候,我們可以看到 主要包括cartorgarpher ros cartographer ceres sover三個部分。其中,ceres solver用於非線性優化,求解最小二乘問題 cartographer ros為ros平台的封裝,獲取感測器資料...

AbstractListView原始碼分析3

normal list that does not indicate choices public static final int choice mode none 0 the list allows up to one choice public static final int choice ...

Android AsyncTask原始碼分析

android中只能在主線程中進行ui操作,如果是其它子執行緒,需要借助非同步訊息處理機制handler。除此之外,還有個非常方便的asynctask類,這個類內部封裝了handler和執行緒池。本文先簡要介紹asynctask的用法,然後分析具體實現。asynctask是乙個抽象類,我們需要建立子...