線程池是什么?線程池與連接池有什么區(qū)別?線程池工作原理是什么?
你好,我是碼哥,可以叫我靚仔。
線程池是一種用于管理和重用線程的機(jī)制,它允許開發(fā)人員有效地執(zhí)行并發(fā)任務(wù)。通過使用線程池,可以帶來了許多好處:
- 資源管理: 線程池能夠有效地管理系統(tǒng)資源,通過限制并發(fā)任務(wù)的數(shù)量和重用線程,減少了線程創(chuàng)建和銷毀的開銷,提高了系統(tǒng)資源利用率。
- 性能提升: 通過合理地配置線程池大小和任務(wù)隊列,可以優(yōu)化任務(wù)執(zhí)行流程,降低了線程的上下文切換成本,提高了任務(wù)的執(zhí)行效率和系統(tǒng)的吞吐量。
- 避免資源耗盡: 線程池可以控制并發(fā)任務(wù)的數(shù)量,防止系統(tǒng)因創(chuàng)建過多線程而導(dǎo)致資源耗盡,從而提高了系統(tǒng)的穩(wěn)定性和可靠性。
- 任務(wù)排隊: 線程池通過任務(wù)隊列來暫存尚未執(zhí)行的任務(wù),保證了任務(wù)的順序執(zhí)行,并且能夠靈活地處理突發(fā)任務(wù)量,避免了系統(tǒng)的過載。
- 簡化并發(fā)編程: 使用線程池可以簡化并發(fā)編程的復(fù)雜性,開發(fā)人員無需手動管理線程的生命周期和任務(wù)的調(diào)度,只需將任務(wù)提交給線程池即可,從而降低了編程的復(fù)雜度和出錯的可能性。
接下來以 Java 中的線程池實現(xiàn)機(jī)制為例,帶你掌握線程池的工作機(jī)制。
線程池的工作機(jī)制
線程池的工作機(jī)制可以看作是一種生產(chǎn)者-消費者模型的應(yīng)用。
在這個模型中,任務(wù)(生產(chǎn)者)被提交到線程池,然后線程池中的線程(消費者)從任務(wù)隊列中取出任務(wù)并執(zhí)行,線程池模型架構(gòu)如下圖:
- 開發(fā)人員使用 ThreadPoolExecutor 的 submit() 方法提交任務(wù)。
- 檢測線程池運行狀態(tài),如果不是 RUNNING,則直接拒絕,線程池要保證在 RUNNING 的狀態(tài)下執(zhí)行任務(wù)
- 提交的任務(wù)(通常實現(xiàn)了 Callable 或 Runnable 接口)會被封裝成一個 FutureTask 對象,該對象實現(xiàn)了 Future 接口,允許獲取任務(wù)執(zhí)行的結(jié)果。
- 如果線程池中的核心線程數(shù)小于核心線程池大小(corePoolSize),則嘗試創(chuàng)建新的核心線程來執(zhí)行任務(wù)。
- 如果當(dāng)前核心線程數(shù)已經(jīng)達(dá)到 corePoolSize,則將任務(wù)放入任務(wù)隊列中,等待工作線程獲取任務(wù)執(zhí)行。
- 如果隊列已滿,而且當(dāng)前線程池中的線程數(shù)量小于最大線程池大?。╩aximumPoolSize),則嘗試創(chuàng)建新的非核心線程來執(zhí)行任務(wù)。
- 如果當(dāng)前線程池中的線程數(shù)量已經(jīng)達(dá)到最大線程池大小,則根據(jù)拒絕策略進(jìn)行處理。
- 任務(wù)執(zhí)行完成后,線程池將返回一個 Future 對象,通過這個對象可以獲取任務(wù)執(zhí)行的結(jié)果。
線程池的執(zhí)行流程圖如下所示。
線程池的狀態(tài)
Java 中的線程池具有不同的狀態(tài),這些狀態(tài)反映了線程池在其生命周期中的不同階段和行為。主要的線程池狀態(tài)有以下幾種:
狀態(tài) | 描述 |
RUNNING(運行中) | 表示線程池正在正常運行,并且可以接受新的任務(wù)提交。在這種狀態(tài)下,線程池可以執(zhí)行任務(wù),并且可以創(chuàng)建新的線程來處理任務(wù)。 |
SHUTDOWN(關(guān)閉中) | 表示線程池正在關(guān)閉中。在這種狀態(tài)下,線程池不再接受新的任務(wù)提交,但會繼續(xù)執(zhí)行已提交的任務(wù),直到所有任務(wù)執(zhí)行完成。 |
STOP(停止) | 表示線程池已經(jīng)停止,不再接受新的任務(wù)提交,并且嘗試中斷正在執(zhí)行的任務(wù)。 |
TERMINATED(終止) | 表示線程池已經(jīng)終止,不再接受新的任務(wù)提交,并且所有任務(wù)已經(jīng)執(zhí)行完成。在這種狀態(tài)下,線程池中的所有線程都已經(jīng)被銷毀。 |
這些狀態(tài)是通過 ThreadPoolExecutor 類中的 ctl(control)字段來維護(hù)的,ctl 是一個 AtomicInteger 類型的變量,它的高 3 位表示線程池的運行狀態(tài),低 29 位表示線程池中的工作線程數(shù)量。
在 ThreadPoolExecutor 中,通過位運算來修改和檢查 ctl 的值,以實現(xiàn)線程池狀態(tài)的轉(zhuǎn)換和管理。
通過 ctl 字段,ThreadPoolExecutor 類能夠高效地維護(hù)線程池的狀態(tài)和線程數(shù)量信息,從而實現(xiàn)了對線程池的有效管理和控制。
要注意的是,線程池的狀態(tài)不是直接設(shè)置的,而是通過調(diào)用 shutdown()、shutdownNow() 等方法觸發(fā)狀態(tài)的轉(zhuǎn)換。
例如,調(diào)用 shutdown() 方法會將線程池的狀態(tài)從 RUNNING 轉(zhuǎn)換為 SHUTDOWN。
拒絕策略
線程池的拒絕策略用于定義當(dāng)線程池已滿并且無法處理新提交的任務(wù)時應(yīng)該采取的行動。以下是 Java 中常見的線程池拒絕策略:
策略名稱 | 描述 |
AbortPolicy(默認(rèn)策略) | 如果線程池已滿并且無法接受新任務(wù),則會拋出 RejectedExecutionException 異常。這是默認(rèn)的拒絕策略。 |
CallerRunsPolicy | 當(dāng)線程池已滿時,會使用提交任務(wù)的線程來執(zhí)行該任務(wù)。換句話說,如果無法接受新任務(wù),則會由提交任務(wù)的線程自己執(zhí)行該任務(wù)。 |
DiscardPolicy | 當(dāng)線程池已滿時,會丟棄掉無法處理的新任務(wù),而不會拋出異常。 |
DiscardOldestPolicy | 當(dāng)線程池已滿時,會丟棄隊列中等待時間最長的任務(wù),然后嘗試將新任務(wù)加入隊列。 |
除了上述標(biāo)準(zhǔn)拒絕策略之外,您還可以實現(xiàn) RejectedExecutionHandler 接口來定義自定義的拒絕策略。這使您能夠根據(jù)應(yīng)用程序的需求實現(xiàn)更復(fù)雜的拒絕邏輯。RejectedExecutionHandler 接口:
public interface RejectedExecutionHandler {
void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
}
提交任務(wù)給線程池觸發(fā)線程池的拒絕策略如下圖所示。
線程池使用場景
Java 線程池在業(yè)務(wù)中有許多實踐應(yīng)用,以下是其中一些常見的實踐方式:
- Web 服務(wù)器:用 Tomcat 作為示例。Tomcat 是一個常見的 Java Web 服務(wù)器,它使用線程池來處理傳入的 HTTP 請求。每當(dāng)有一個新的 HTTP 請求到達(dá) Tomcat 服務(wù)器時,Tomcat 會從預(yù)先配置的線程池中獲取一個線程來處理該請求。這樣可以有效地管理并發(fā)請求,提高服務(wù)器的響應(yīng)速度和穩(wěn)定性。
- 并發(fā)任務(wù)處理:許多業(yè)務(wù)場景需要處理大量的并發(fā)任務(wù),例如數(shù)據(jù)處理、文件上傳下載、消息處理等。線程池可以用于并發(fā)處理這些任務(wù),提高任務(wù)的執(zhí)行效率和系統(tǒng)的吞吐量。
- 異步處理:在某些業(yè)務(wù)場景中,需要執(zhí)行一些耗時的操作,但不想讓主線程阻塞。線程池可以用于異步執(zhí)行這些操作,例如發(fā)送郵件、短信通知、數(shù)據(jù)分析等。通過將任務(wù)提交給線程池,主線程可以立即返回,而任務(wù)會在后臺線程中異步執(zhí)行。
線程池和連接池的區(qū)別
連接池是一組預(yù)先初始化和可重復(fù)使用的數(shù)據(jù)庫連接。它用于管理到數(shù)據(jù)庫的連接池,允許多個客戶端共享和重復(fù)使用數(shù)據(jù)庫連接。
連接池有助于通過減少建立和關(guān)閉數(shù)據(jù)庫連接的開銷來提高數(shù)據(jù)庫密集型應(yīng)用程序的性能和可伸縮性。
線程池和連接池都是用于提高系統(tǒng)性能和資源利用率的重要技術(shù),但它們的主要區(qū)別在于應(yīng)用場景和管理的資源類型。
線程池用于管理可重復(fù)使用的線程資源,以便有效地執(zhí)行并發(fā)任務(wù),而連接池則用于管理可重復(fù)使用的數(shù)據(jù)庫連接資源,以便高效地處理數(shù)據(jù)庫訪問。
如下圖是數(shù)據(jù)庫連接池工作機(jī)制。