首頁 Java java教程 Java 執行緒池框架核心程式碼分析

Java 執行緒池框架核心程式碼分析

Dec 05, 2016 am 11:44 AM
java

多執行緒程式設計中,為每個任務分配一個執行緒是不切實際的,執行緒所建立的開銷和資源消耗都是很高的。線程池應運而生,成為我們管理線程的利器。 Java 透過Executor接口,提供了一種標準的方法將任務的提交過程和執行過程解耦開來,並用Runnable表示任務。

下面,我們來分析一下 Java 執行緒池框架的實作ThreadPoolExecutor。

下面的分析是基於JDK1.7

生命週期

ThreadPoolExecutor中,使用CAPACITY的高3位來表示運行狀態,分別是:

RUNNING:接收新任務,並且處理任務隊列中的任務隊列中的任務不接收新任務,但處理任務佇列的任務 
STOP:不接收新任務,不出來任務佇列,同時中斷所有進行中的任務 
TIDYING:所有任務已經被終止,工作執行緒數量為0,到達該狀態會執行terminated() 
TERMINATED:terminated()執行完畢 

Java 執行緒池框架核心程式碼分析

ThreadPoolExecutor中用原子類別來表示狀態位元

private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
登入後複製
,則值為0) 

maximumPoolSize:最大的執行緒數量,受限於CAPACITY 

keepAliveTime:對應執行緒的存活時間,時間單位由TimeUnit指定 

workQueue:工作佇列,儲存待執行的任務線程池滿後會觸發 

線程池的最大容量:CAPACITY中的前三位用作標誌位,也就是說工作線程的最大容量為(2^29)-1

四種型號

CachedThreadPool:一個可快取的線程池,如果線程池的當前規模超過了處理需求時,那麼將回收空閒的線程,當需求增加時,則可以添加新的線程,線程池的規模不存在任何的限制。 
FixedThreadPool:一個固定大小的執行緒池,提交一個任務時就會建立一個線程,直到達到執行緒池的最大數量,此時執行緒池的大小將不再改變。 
SingleThreadPool:一個單一執行緒的執行緒池,它只有一個工作執行緒來執行任務,可以確保按照任務在佇列中的順序來串列執行,如果這個執行緒異常結束會建立一個新的執行緒來執行任務。 
ScheduledThreadPool:固定大小的執行緒池,並且以延遲或定時的方式來執行任務,類似於Timer。當狀態是否處於RUNNING 

如果否,則拒絕該任務 

如果是,判斷目前執行緒數量是否為0,如果為0,就增加一個工作執行緒。

開啟普通執行緒執行任務addWorker(command, false),開啟失敗就拒絕該任務 

從上面的分析可以總結出執行緒池運作的四個階段:

poolSize < corePoolSize 且佇列為空,此時會新建執行緒來處理提交的任務 
poolSize == corePoolSize,此時提交的任務進入工作隊列,工作執行緒從佇列中取得任務執行,此時佇列不為空且未滿。
poolSize == corePoolSize,且佇列已滿,此時也會新建執行緒來處理提交的任務,但是poolSize < maxPoolSize 

poolSize == maxPoolSize,並且佇列已滿,此時會觸發拒絕策略 

拒絕策略

我們提到任務無法執行會被拒絕,RejectedExecutionHandler是處理被拒絕任務的介面。以下是四種拒絕策略。

AbortPolicy:預設策略,終止任務,拋出RejectedException 
CallerRunsPolicy:在呼叫者執行目前任務,不拋棄異常 
DiscardPolicy:丟棄策略,直接丟棄任務,不丟棄目前任務,不拋異常

執行緒池中的Worker

Worker繼承了AbstractQueuedSynchronizer和Runnable,前者給Worker提供鎖的功能,後者執行工作執行緒的主要方法runWorker(Workerker w)(從任務佇列任務執行)。 Worker 引用存在workers集合裡面,用mainLock守護。

private final ReentrantLock mainLock = new ReentrantLock();
private final HashSet<Worker> workers = new HashSet<Worker>();
登入後複製

核心函數 runWorker

下面是簡化的邏輯,注意:每個工作執行緒的run都執行下面的函數

final void runWorker(Worker w) {
    Thread wt = Thread.currentThread();
    Runnable task = w.firstTask;
    w.firstTask = null;    while (task != null || (task = getTask()) != null) {
        w.lock();
        beforeExecute(wt, task);        
        task.run();
        afterExecute(task, thrown);
        w.unlock();
    }
    processWorkerExit(w, completedAbruptly);
}
登入後複製

从getTask()中获取任务
锁住 worker
执行beforeExecute(wt, task),这是ThreadPoolExecutor提供给子类的扩展方法
运行任务,如果该worker有配置了首次任务,则先执行首次任务且只执行一次。
执行afterExecute(task, thrown);
解锁 worker
如果获取到的任务为 null,关闭 worker
获取任务 getTask

线程池内部的任务队列是一个阻塞队列,具体实现在构造时传入。

private final BlockingQueue<Runnable> workQueue;
登入後複製

getTask()从任务队列中获取任务,支持阻塞和超时等待任务,四种情况会导致返回null,让worker关闭。

现有的线程数量超过最大线程数量
线程池处于STOP状态
线程池处于SHUTDOWN状态且工作队列为空
线程等待任务超时,且线程数量超过保留线程数量
核心逻辑:根据timed在阻塞队列上超时等待或者阻塞等待任务,等待任务超时会导致工作线程被关闭。

timed = allowCoreThreadTimeOut || wc > corePoolSize;Runnable r = timed ?
    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
    workQueue.take();
登入後複製

在以下两种情况下等待任务会超时:

允许核心线程等待超时,即allowCoreThreadTimeOut(true) 
当前线程是普通线程,此时wc > corePoolSize 
工作队列使用的是BlockingQueue,这里就不展开了,后面再写一篇详细的分析。

总结

ThreadPoolExecutor基于生产者-消费者模式,提交任务的操作相当于生产者,执行任务的线程相当于消费者。 
Executors提供了四种基于ThreadPoolExecutor构造线程池模型的方法,除此之外,我们还可以直接继承ThreadPoolExecutor,重写beforeExecute和afterExecute方法来定制线程池任务执行过程。 
使用有界队列还是无界队列需要根据具体情况考虑,工作队列的大小和线程的数量也是需要好好考虑的。 
拒绝策略推荐使用CallerRunsPolicy,该策略不会抛弃任务,也不会抛出异常,而是将任务回退到调用者线程中执行。


本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱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

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

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1672
14
CakePHP 教程
1428
52
Laravel 教程
1332
25
PHP教程
1277
29
C# 教程
1257
24
PHP與Python:了解差異 PHP與Python:了解差異 Apr 11, 2025 am 12:15 AM

PHP和Python各有優勢,選擇應基於項目需求。 1.PHP適合web開發,語法簡單,執行效率高。 2.Python適用於數據科學和機器學習,語法簡潔,庫豐富。

PHP:網絡開發的關鍵語言 PHP:網絡開發的關鍵語言 Apr 13, 2025 am 12:08 AM

PHP是一種廣泛應用於服務器端的腳本語言,特別適合web開發。 1.PHP可以嵌入HTML,處理HTTP請求和響應,支持多種數據庫。 2.PHP用於生成動態網頁內容,處理表單數據,訪問數據庫等,具有強大的社區支持和開源資源。 3.PHP是解釋型語言,執行過程包括詞法分析、語法分析、編譯和執行。 4.PHP可以與MySQL結合用於用戶註冊系統等高級應用。 5.調試PHP時,可使用error_reporting()和var_dump()等函數。 6.優化PHP代碼可通過緩存機制、優化數據庫查詢和使用內置函數。 7

突破或從Java 8流返回? 突破或從Java 8流返回? Feb 07, 2025 pm 12:09 PM

Java 8引入了Stream API,提供了一種強大且表達力豐富的處理數據集合的方式。然而,使用Stream時,一個常見問題是:如何從forEach操作中中斷或返回? 傳統循環允許提前中斷或返回,但Stream的forEach方法並不直接支持這種方式。本文將解釋原因,並探討在Stream處理系統中實現提前終止的替代方法。 延伸閱讀: Java Stream API改進 理解Stream forEach forEach方法是一個終端操作,它對Stream中的每個元素執行一個操作。它的設計意圖是處

PHP與其他語言:比較 PHP與其他語言:比較 Apr 13, 2025 am 12:19 AM

PHP適合web開發,特別是在快速開發和處理動態內容方面表現出色,但不擅長數據科學和企業級應用。與Python相比,PHP在web開發中更具優勢,但在數據科學領域不如Python;與Java相比,PHP在企業級應用中表現較差,但在web開發中更靈活;與JavaScript相比,PHP在後端開發中更簡潔,但在前端開發中不如JavaScript。

PHP與Python:核心功能 PHP與Python:核心功能 Apr 13, 2025 am 12:16 AM

PHP和Python各有優勢,適合不同場景。 1.PHP適用於web開發,提供內置web服務器和豐富函數庫。 2.Python適合數據科學和機器學習,語法簡潔且有強大標準庫。選擇時應根據項目需求決定。

PHP的影響:網絡開發及以後 PHP的影響:網絡開發及以後 Apr 18, 2025 am 12:10 AM

PHPhassignificantlyimpactedwebdevelopmentandextendsbeyondit.1)ItpowersmajorplatformslikeWordPressandexcelsindatabaseinteractions.2)PHP'sadaptabilityallowsittoscaleforlargeapplicationsusingframeworkslikeLaravel.3)Beyondweb,PHPisusedincommand-linescrip

PHP:許多網站的基礎 PHP:許多網站的基礎 Apr 13, 2025 am 12:07 AM

PHP成為許多網站首選技術棧的原因包括其易用性、強大社區支持和廣泛應用。 1)易於學習和使用,適合初學者。 2)擁有龐大的開發者社區,資源豐富。 3)廣泛應用於WordPress、Drupal等平台。 4)與Web服務器緊密集成,簡化開發部署。

PHP與Python:用例和應用程序 PHP與Python:用例和應用程序 Apr 17, 2025 am 12:23 AM

PHP適用於Web開發和內容管理系統,Python適合數據科學、機器學習和自動化腳本。 1.PHP在構建快速、可擴展的網站和應用程序方面表現出色,常用於WordPress等CMS。 2.Python在數據科學和機器學習領域表現卓越,擁有豐富的庫如NumPy和TensorFlow。

See all articles