Executor框架及各個成員總結

Executor框架的兩級調度模型

在HotSpot VM的線程模型中砚偶,Java線程(java.lang.Thread)被一對一映射為本地操作系統(tǒng)線程来候。Java線程啟動時會創(chuàng)建一個本地操作系統(tǒng)線程致讥;當該Java線程終止時,這個操作系統(tǒng)線程也會被回收名船。操作系統(tǒng)會調度所有線程并將它們分配給可用的CPU幔虏。

在上層,Java多線程程序通常把應用分解為若干個任務捂掰,然后使用用戶級的調度器

(Executor框架)將這些任務映射為固定數量的線程;在底層这嚣,操作系統(tǒng)內核將這些線程映射到硬件處理器上。
image

應用程序通過Executor框架控制上層的調度姐帚;而下層的調度由操作系統(tǒng)內核控制,下層的調度不受應用程序的控制膳汪。

1.Executor框架的結構

image

Executor框架主要由3大部分組成如下:

1、任務遗嗽。包括被執(zhí)行任務需要實現的接口:Runnable接口或Callable接口。

2痹换、任務的執(zhí)行。包括任務執(zhí)行機制的核心接口Executor娇豫,以及繼承自Executor的
ExecutorService接口。Executor框架有兩個關鍵類實現了ExecutorService接口
(ThreadPoolExecutor和ScheduledThreadPoolExecutor)锤躁。

3、異步計算的結果或详。包括接口Future和實現Future接口的FutureTask類系羞。

下面是這些類和接口的簡介。

·Executor是一個接口霸琴,它是Executor框架的基礎椒振,它將任務的提交與任務的執(zhí)行分離開來。
·ThreadPoolExecutor是線程池的核心實現類梧乘,用來執(zhí)行被提交的任務澎迎。

·ScheduledThreadPoolExecutor是一個實現類,可以在給定的延遲后運行命令选调,或者定期執(zhí)行命令夹供。ScheduledThreadPoolExecutor比Timer更靈活,功能更強大仁堪。

Future接口和實現Future接口的FutureTask類哮洽,代表異步計算的結果。

·Runnable和Callable接口實現類都可被ThreadPoolExecutor或Scheduled-ThreadPoolExecutor執(zhí)行弦聂。
下面來看下使用示意圖:

image

主線程首先要創(chuàng)建實現Runnable或者Callable接口的任務對象鸟辅。工具類Executors可以把一
個Runnable對象封裝為一個Callable對象(Executors.callable(Runnable task)或
Executors.callable(Runnable task,Object resule))莺葫。

然后可以把Runnable對象直接交給ExecutorService執(zhí)行(ExecutorService.execute(Runnable
command))匪凉;或者也可以把Runnable對象或Callable對象提交給ExecutorService執(zhí)行(Executor-
Service.submit(Runnable task)或ExecutorService.submit(Callable<T>task))。

如果執(zhí)行ExecutorService.submit(…)捺檬,ExecutorService將返回一個實現Future接口的對象
(到目前為止的JDK中再层,返回的是FutureTask對象)。由于FutureTask實現了Runnable,程序員也可
以創(chuàng)建FutureTask树绩,然后直接交給ExecutorService執(zhí)行萨脑。

最后,主線程執(zhí)行FutureTask.get()方法來等待任務執(zhí)行完成饺饭。主線程也可以執(zhí)行FutureTask.cancel(boolean mayInterruptIfRunning)來取消此任務的執(zhí)行渤早。

Executor框架的成員

主要介紹Executor框架的主要成員:ThreadPoolExecutor、ScheduledThreadPoolExecutor瘫俊、
Future接口鹊杖、Runnable接口、Callable接口和Executors扛芽。

(1)ThreadPoolExecutor(想深入理解實現原理可以看這篇文章:https://juejin.im/post/5d67e5b4e51d4561f64a0849)
ThreadPoolExecutor通常使用工廠類Executors來創(chuàng)建。Executors可以創(chuàng)建3種類型的
ThreadPoolExecutor:SingleThreadExecutor川尖、FixedThreadPool和CachedThreadPool。

下面分別介紹這3種ThreadPoolExecutor被芳。

(1) ThreadPoolExecutor

(1)FixedThreadPool畔濒。

是Executors提供的侵状,創(chuàng)建使用固定線程數的FixedThreadPool的API趣兄。

public static ExecutorService newFixedThreadPool(int nThreads)
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactorythreadFactory

FixedThreadPool適用于為了滿足資源管理的需求诽俯,而需要限制當前線程數量的應用場景承粤,它適用于負載比較重的服務器辛臊。

(2)SingleThreadExecutor

下面是Executors提供的彻舰,創(chuàng)建使用單個線程的SingleThread-Executor的API。

public static ExecutorService newSingleThreadExecutor()
public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory)

SingleThreadExecutor適用于需要保證順序地執(zhí)行各個任務隔心;并且在任意時間點硬霍,不會有多個線程是活動的應用場景唯卖。

(3)CachedThreadPool拜轨。

下面是Executors提供的,創(chuàng)建一個會根據需要創(chuàng)建新線程的CachedThreadPool的API卵沉。

public static ExecutorService newCachedThreadPool()
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory)

CachedThreadPool是大小無界的線程池偎箫,適用于執(zhí)行很多的短期異步任務的小程序,或者是負載較輕的服務器恶复。

(2)ScheduledThreadPoolExecutor

ScheduledThreadPoolExecutor通常使用工廠類Executors來創(chuàng)建谤牡。Executors可以創(chuàng)建2種類型的ScheduledThreadPoolExecutor.

如下:
·ScheduledThreadPoolExecutor翅萤。包含若干個線程的ScheduledThreadPoolExecutor腊满。
·SingleThreadScheduledExecutor碳蛋。只包含一個線程的ScheduledThreadPoolExecutor肃弟。

下面是工廠類Executors提供的,創(chuàng)建固定個數線程的ScheduledThreadPoolExecutor的API穷缤。

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize,ThreadFactory)

ScheduledThreadPoolExecutor適用于需要多個后臺線程執(zhí)行周期任務津肛,同時為了滿足資源管理的需求而需要限制后臺線程的數量的應用場景快耿。

下面是Executors提供的掀亥,創(chuàng)建單個線程的SingleThreadScheduledExecutor的API

public static ScheduledExecutorService newSingleThreadScheduledExecutor()
public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory)

SingleThreadScheduledExecutor適用于需要單個后臺線程執(zhí)行周期任務搪花,同時需要保證順序地執(zhí)行各個任務的應用場景撮竿。

(3)Future接口

Future接口和實現Future接口的FutureTask類用來表示異步計算的結果。當我們把Runnable
接口或Callable接口的實現類提交(submit)給ThreadPoolExecutor或ScheduledThreadPoolExecutor時髓需,ThreadPoolExecutor或ScheduledThreadPoolExecutor會向我們返回一個FutureTask對象僚匆。

<T> Future<T> submit(Callable<T> task)
<T> Future<T> submit(Runnable task, T result)
Future<> submit(Runnable task)

FutureTask是Future的子類咧擂。
有一點需要讀者注意松申,到目前最新的JDK8為止贸桶,Java通過上述API返回的是一個FutureTask對象刨啸。但從API可以看到识脆,Java僅僅保證返回的是一個實現了Future接口的對象。在將來的JDK實現中换团,返回的可能不一定是FutureTask宫蛆。

(4)Runnable接口和Callable接口

Runnable接口和Callable接口的實現類耀盗,都可以被ThreadPoolExecutor或Scheduled-
ThreadPoolExecutor執(zhí)行叛拷。它們之間的區(qū)別是Runnable不會返回結果忿薇,而Callable可以返回結
果。

除了可以自己創(chuàng)建實現Callable接口的對象外揉燃,還可以使用工廠類Executors來把一個
Runnable包裝成一個Callable炊汤。

下面是Executors提供的抢腐,把一個Runnable包裝成一個Callable的API。

public static Callable<Object> callable(Runnable task)

下面是Executors提供的婿着,把一個Runnable和一個待返回的結果包裝成一個Callable的API醋界。

public static <T> Callable<T> callable(Runnable task, T result) // 假設返回對象Callable2

當我們把一個Callable對象(比如上面的Callable1或Callable2)提交給
ThreadPoolExecutor或ScheduledThreadPoolExecutor執(zhí)行時,submit(…)會向我們返回一個
FutureTask對象丘侠。我們可以執(zhí)行FutureTask.get()方法來等待任務執(zhí)行完成。

當任務成功完成后FutureTask.get()將返回該任務的結果蜗字。例如,如果提交的是對象Callable1挪捕,FutureTask.get()方法將返回null;如果提交的是對象Callable2级零,FutureTask.get()方法將返回result對象。

ThreadPoolExecutor詳解

可以看這兩篇文章:

從源碼來看JDK8線程池ThreadPoolExecutor的實現原理(一)
https://juejin.im/post/5d67e5b4e51d4561f64a0849

從源碼來看JDK8線程池ThreadPoolExecutor的實現原理(二)
https://juejin.im/post/5d688686e51d4561ce5a1c8b

·通過Executor框架的工具類Executors鉴嗤,可以創(chuàng)建3種類型的ThreadPoolExecutor。

·FixedThreadPool醉锅。

·SingleThreadExecutor。

·CachedThreadPool荣挨。

下面將分別介紹這3種ThreadPoolExecutor

FixedThreadPool詳解

FixedThreadPool被稱為可重用固定線程數的線程池朴摊。下面是FixedThreadPool的源代碼實現。

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
}

FixedThreadPool的corePoolSize和maximumPoolSize都被設置為創(chuàng)建FixedThreadPool時指定的參數nThreads甚纲。

FixedThreadPool的execute()方法的運行示意圖:

image

1)如果當前運行的線程數少于corePoolSize介杆,則創(chuàng)建新線程來執(zhí)行任務。

2)在線程池完成預熱之后(當前運行的線程數等于corePoolSize)荆隘,將任務加入LinkedBlockingQueue椰拒。

3)線程執(zhí)行完1中的任務后凰荚,會在循環(huán)中反復從LinkedBlockingQueue獲取任務來執(zhí)行便瑟。
FixedThreadPool使用無界隊列LinkedBlockingQueue作為線程池的工作隊列(隊列的容量為
Integer.MAX_VALUE)到涂。

FixedThreadPool使用無界隊列作為工作隊列會對線程池帶來如下影響:

1)當線程池中的線程數達到corePoolSize后颁督,新任務將在無界隊列中等待适篙,因此線程池中
的線程數不會超過corePoolSize嚷节。
2)由于1虎锚,使用無界隊列時maximumPoolSize將是一個無效參數窜护。
3)由于1和2柱徙,使用無界隊列時keepAliveTime將是一個無效參數。
4)由于使用無界隊列敌完,運行中的FixedThreadPool(未執(zhí)行方法shutdown()或
shutdownNow())不會拒絕任務(不會調用RejectedExecutionHandler.rejectedExecution方法)滨溉。

SingleThreadExecutor詳解

SingleThreadExecutor是使用單個worker線程的Executor晦攒。

public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>()));
}

SingleThreadExecutor的corePoolSize和maximumPoolSize被設置為1得哆。其他參數與
FixedThreadPool相同贩据。SingleThreadExecutor使用無界隊列LinkedBlockingQueue作為線程池的工
作隊列(隊列的容量為Integer.MAX_VALUE)乐设。SingleThreadExecutor使用無界隊列作為工作隊列
對線程池帶來的影響與FixedThreadPool相同.

image

執(zhí)行流程:

1)如果當前運行的線程數少于corePoolSize(即線程池中無運行的線程)近尚,則創(chuàng)建一個新線
程來執(zhí)行任務戈锻。

2)在線程池完成預熱之后(當前線程池中有一個運行的線程),將任務加入Linked-
BlockingQueue哈街。

3)線程執(zhí)行完1中的任務后拒迅,會在一個無限循環(huán)中反復從LinkedBlockingQueue獲取任務來
執(zhí)行璧微。

3、CachedThreadPool詳解

CachedThreadPool是一個會根據需要創(chuàng)建新線程的線程池胞得。下面是創(chuàng)建CachedThread-Pool的源代碼阶剑。

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());
}

CachedThreadPool的corePoolSize被設置為0危号,即corePool為空葱色;maximumPoolSize被設置為Integer.MAX_VALUE苍狰,即maximumPool是無界的。這里把keepAliveTime設置為60L俐填,意味著CachedThreadPool中的空閑線程等待新任務的最長時間為60秒英融,空閑線程超過60秒后將會被終止驶悟。FixedThreadPool和SingleThreadExecutor使用無界隊列LinkedBlockingQueue作為線程池的工作隊列痕鳍。

CachedThreadPool使用沒有容量的SynchronousQueue作為線程池的工作隊列笼呆,但CachedThreadPool的maximumPool是無界的。這意味著汗茄,如果主線程提交任務的速度高于maximumPool中線程處理任務的速度時洪碳,CachedThreadPool會不斷創(chuàng)建新線程偶宫。極端情況下纯趋,CachedThreadPool會因為創(chuàng)建過多線程而耗盡CPU和內存資源吵冒。

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末痹栖,一起剝皮案震驚了整個濱河市揪阿,隨后出現的幾起案子咆畏,更是在濱河造成了極大的恐慌旧找,老刑警劉巖钮蛛,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件岭辣,死亡現場離奇詭異沦童,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進店門渣刷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鹦肿,“玉大人,你說我怎么就攤上這事辅柴÷崂#” “怎么了?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵碌嘀,是天一觀的道長涣旨。 經常有香客問我,道長股冗,這世上最難降的妖魔是什么霹陡? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮止状,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己伏社,他們只是感情好高蜂,可當我...
    茶點故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布烘跺。 她就那樣靜靜地躺著,像睡著了一般汇歹。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天霎烙,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的鸯绿。 我是一名探鬼主播租幕,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了淑际?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤强品,失蹤者是張志新(化名)和其女友劉穎夫晌,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體蜈亩,經...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡毅戈,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了施流。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片银受。...
    茶點故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖吐限,靈堂內的尸體忽然破棺而出舀寓,到底是詐尸還是另有隱情判莉,我是刑警寧澤,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站自脯,受9級特大地震影響油额,放射性物質發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望份汗。 院中可真熱鬧,春花似錦寄猩、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽淮菠。三九已至澄阳,卻和暖如春低剔,著一層夾襖步出監(jiān)牢的瞬間襟齿,已是汗流浹背钓试。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工疚颊, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓返十,卻偏偏與公主長得像,于是被迫代替她去往敵國和親椭微。 傳聞我的和親對象是個殘疾皇子洞坑,可洞房花燭夜當晚...
    茶點故事閱讀 44,864評論 2 354

推薦閱讀更多精彩內容

  • 一 用線程池好處 限制和管理資源(執(zhí)行任務)。 維護統(tǒng)計信息蝇率,如已完成任務數迟杂。 1)重復利用已創(chuàng)建線程降低線程創(chuàng)建...
    hedgehog1112閱讀 828評論 0 0
  • 為什么要用線程池 關于為什么要使用多線程,請參考【多線程與并發(fā)】:線程的創(chuàng)建本慕、狀態(tài)排拷、方法中的最后一點。 那為什么要...
    maxwellyue閱讀 550評論 0 1
  • 概述 Java的線程既是工作單元锅尘,也是執(zhí)行機制监氢。從JDK 5開始,把工作單元與執(zhí)行機制分離開來藤违。工作單元包括Run...
    康俊1024閱讀 283評論 0 0
  • Executor 框架結構 Executor 框架主要由 3 大部分組成如下浪腐。任務。包括被執(zhí)行任務需要實現的接口:...
    MPPC閱讀 449評論 0 0
  • 前言 最近在看并發(fā)編程藝術這本書顿乒,對看書的一些筆記及個人工作中的總結议街。 Java的線程既是工作單元,也是執(zhí)行機制璧榄。...
    二月_春風閱讀 348評論 0 0