線程池 - ThreadPoolExecutor

使用線程池的好處

1话速、降低資源消耗:通過重復(fù)利用已經(jīng)創(chuàng)建的線程降低線程的創(chuàng)建和銷毀造成的消耗雄可。
2、提高響應(yīng)速度:當(dāng)任務(wù)到達(dá)時(shí)蕴侣,任務(wù)可以不需要等到線程創(chuàng)建就立即執(zhí)行焰轻。
3、提高線程的可管理性:使用線程池可以對(duì)線程資源進(jìn)行統(tǒng)一分配昆雀、調(diào)優(yōu)和監(jiān)控辱志。

構(gòu)造(創(chuàng)建線程池)

ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue)
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler)
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory)
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)

參數(shù)含義

1、corePoolSize:線程池的基本大小狞膘,當(dāng)一個(gè)任務(wù)提交到線程池時(shí)揩懒,線程池會(huì)創(chuàng)建一個(gè)線程來執(zhí)行任務(wù),其它空閑的基本線程也能夠繼續(xù)執(zhí)行新任務(wù)創(chuàng)建新線程挽封,等到需要執(zhí)行的任務(wù)數(shù)大于線程池基本大小時(shí)就不會(huì)再創(chuàng)建已球。
2、maximumPoolSize:線程池允許的最大線程數(shù),如果隊(duì)列滿了和悦,并且已創(chuàng)建的線程數(shù)小于最大線程數(shù)即碗,則線程池會(huì)再創(chuàng)建新的線程執(zhí)行任務(wù)望伦。
3泊脐、keepAliveTime:線程池的工作線程空閑后窜护,保持存活的時(shí)間墙懂。如果任務(wù)很多度迂,并且每個(gè)任務(wù)執(zhí)行的時(shí)間比較短侨嘀,可以把這個(gè)時(shí)間調(diào)大一點(diǎn)妨猩,提高線程的利用率燕差。
4遭笋、unit:線程活動(dòng)保持時(shí)間的單位
5、workQueue:任務(wù)隊(duì)列徒探,用于保存等待執(zhí)行的任務(wù)的阻塞隊(duì)列瓦呼。可選隊(duì)列如下:
??5.1测暗、ArrayBlockingQueue:基于數(shù)組結(jié)構(gòu)的有界阻塞隊(duì)列央串,遵循FIFO原則。
??5.2碗啄、LinkedBlockingQueue:基于鏈表結(jié)構(gòu)的阻塞隊(duì)列质和,遵循FIFO原則。
??5.3稚字、SynchronousQueue:不存儲(chǔ)元素的阻塞隊(duì)列饲宿,每一個(gè)插入必須等到另一個(gè)線程調(diào)用移除操作,否則插入操作會(huì)一直處于阻塞狀態(tài)胆描。
??5.4瘫想、PriorityBlockingQueue:具有優(yōu)先級(jí)的無限阻塞隊(duì)列。
6昌讲、handler:飽和策略国夜,當(dāng)隊(duì)列和線程池都滿了,線程池處于飽和狀態(tài)剧蚣,那么必須采取一種策略處理提交的新任務(wù)支竹。默認(rèn)使用AbortPolicy○矗可選策略如下:
??6.1礼搁、AbortPolicy:無法處理新任務(wù)時(shí)直接拋出異常。
??6.2目尖、CallerRunsPolicy:直接在調(diào)用者的調(diào)用線程中運(yùn)行任務(wù)馒吴。
??6.3、DiscardOldestPolicy:丟棄最舊的未處理請(qǐng)求,并執(zhí)行當(dāng)前任務(wù)饮戳。
??6.4豪治、DiscardPolicy:直接丟棄任務(wù)。
7扯罐、threadFactory:設(shè)置創(chuàng)建線程的工廠负拟,可以使用的工廠有:
ThreadFactory()Executors.privilegedThreadFactory()歹河、Executors.defaultThreadFactory()等等

線程池處理流程

處理流程.png

1掩浙、當(dāng)任務(wù)提交到線程池后,先判斷當(dāng)前運(yùn)行的線程是否少于corePoolSize:
??少于 > 創(chuàng)建新線程來執(zhí)行任務(wù)
??大于 > 將任務(wù)加入到任務(wù)隊(duì)列
2秸歧、加入任務(wù)隊(duì)列時(shí)判斷任務(wù)隊(duì)列是否已滿:
??未滿 > 加入任務(wù)隊(duì)列
??已滿 > 創(chuàng)建新的線程來執(zhí)行任務(wù)
3厨姚、隊(duì)列已滿,新建線程執(zhí)行任務(wù)時(shí)判斷當(dāng)前運(yùn)行的線程是否超出了maximumPoolSize:
??未超出 > 新建線程執(zhí)行任務(wù)
??超出 > 拒絕任務(wù)键菱,執(zhí)行所選的飽和策略

線程池中線程執(zhí)行任務(wù)示意圖

線程池中線程執(zhí)行任務(wù)示意圖
  • 任務(wù)提交到線程池后谬墙,新建一個(gè)線程執(zhí)行任務(wù)
  • 任務(wù)執(zhí)行完后,會(huì)反復(fù)從任務(wù)隊(duì)列中獲取任務(wù)來執(zhí)行

ThreadPoolExecutor 方法

類型 方法 描述
protected void afterExecute(Runnable r, Throwable t) 任務(wù)執(zhí)行結(jié)束后調(diào)用
protected void beforeExecute(Runnable r, Throwable t) 任務(wù)執(zhí)行之前調(diào)用
void allowCoreThreadTimeOut(boolean value) 設(shè)置用于控制在保持活動(dòng)時(shí)間內(nèi)沒有任務(wù)到達(dá)時(shí)核心線程是否可能超時(shí)并終止的策略经备,并在新任務(wù)到達(dá)時(shí)根據(jù)需要替換
boolean allowsCoreThreadTimeOut() 如果此池允許核心線程超時(shí)拭抬,并且在keepAlive時(shí)間內(nèi)沒有任務(wù)到達(dá)時(shí)終止,返回true
boolean awaitTermination(long timeout, TimeUnit unit) 阻塞直到所有任務(wù)在關(guān)閉請(qǐng)求后完成執(zhí)行弄喘,或發(fā)生超時(shí)玖喘,或當(dāng)前線程中斷
void execute(Runnable command) 提交不需要返回值的任務(wù)
protected void finalize() 當(dāng)該執(zhí)行程序不再被引用并且沒有線程時(shí),調(diào)用shutdown
int getActiveCount() 獲取活動(dòng)的線程數(shù)
long getCompletedTaskCount() 獲取線程池在運(yùn)行過程中完成的任務(wù)數(shù)量
int getCorePoolSize() 獲取核心線程數(shù)
long getKeepAliveTime(TimeUnit unit) 獲取線程保持活動(dòng)時(shí)間
int getLargestPoolSize() 獲取線程池中曾經(jīng)創(chuàng)建過的最大線程數(shù)量蘑志,通過這個(gè)數(shù)據(jù)可以判斷線程池曾經(jīng)是否滿過
int getMaximumPoolSize() 獲取允許的最大線程數(shù)
int getQueue() 獲取線程池中的當(dāng)前線程數(shù)
BlockingQueue<Runnable> getPoolSize() 返回執(zhí)行任務(wù)使用的任務(wù)隊(duì)列
RejectedExecutionHandler getRejectedExecutionHandler() 返回?zé)o法執(zhí)行任務(wù)的處理程序
long getTaskCount() 獲取線程池需要執(zhí)行的線程數(shù)量
ThreadFactory getThreadFactory() 返回用于創(chuàng)建新線程的線程工廠
boolean isShutdown() 當(dāng)調(diào)用了線程池的shutdown或者shutdownNow后累奈,調(diào)用isShutdown()返回true
boolean isTerminated() 當(dāng)所有任務(wù)都關(guān)閉后,才表示線程池關(guān)閉成功急但,調(diào)用isTerminated()返回true
boolean isTerminating() 當(dāng)調(diào)用了線程池的shutdown或者shutdownNow后澎媒,任務(wù)還沒有全部結(jié)束,調(diào)用isTerminating()返回true
int prestartAllCoreThreads() 提前創(chuàng)建并啟動(dòng)所有核心線程波桩,使它們空閑地等待工作
boolean prestartCoreThread() 啟動(dòng)一個(gè)核心線程戒努,使其閑置地等待工作
void purge() 嘗試從工作隊(duì)列中刪除所有已取消的未來任務(wù)
boolean remove(Runnable task) 如果執(zhí)行程序的任務(wù)隊(duì)列中存在此任務(wù),則將其刪除
void setCorePoolSize(int corePoolSize) 設(shè)置核心線程數(shù)
void setKeepAliveTime(long time, TimeUnit unit) 設(shè)置線程閑置后存活時(shí)間
void setMaximumPoolSize(int maximumPoolSize) 設(shè)置允許的最大線程數(shù)
void setRejectedExecutionHandler(RejectedExecutionHandler handler) 為無法執(zhí)行的任務(wù)設(shè)置新的處理程序
void setThreadFactory(ThreadFactory threadFactory) 設(shè)置用于創(chuàng)建新線程的線程工廠
void shutdown() 將線程池設(shè)置成shutdown狀態(tài)镐躲,然后中斷所有沒有正在執(zhí)行的線程
List<Runnable> shutdownNow() 首先將線程池設(shè)置成stop狀態(tài)储玫,然后嘗試停止所有正在執(zhí)行的任務(wù),暫停正在等待的任務(wù)萤皂,并返回正在等待執(zhí)行的任務(wù)的列表
protected void terminated() 執(zhí)行程序終止時(shí)調(diào)用的方法
String toString() 返回線程池狀態(tài)撒穷、任務(wù)數(shù)等信息的字符串

提交任務(wù)方式

  • execute()提交不需要返回值的任務(wù)
  • submit() 提交需要返回值的任務(wù)

關(guān)閉線程池方式

  • shutdownNow() 首先將線程池設(shè)置成stop狀態(tài),然后嘗試停止所有正在執(zhí)行的任務(wù)裆熙,暫停正在等待的任務(wù)端礼,并返回正在等待執(zhí)行的任務(wù)的列表
  • shutdown() 將線程池設(shè)置成shutdown狀態(tài)禽笑,然后中斷所有沒有正在執(zhí)行的線程

例子

package com.sy.thread.example;


import java.util.concurrent.*;

/**
 * Description: thread
 *
 * @author songyu
 */
public class ThreadPoolExecutorTest1 {
    public static void main(String[] args) {
        //定義創(chuàng)建線程使用工廠
        ThreadFactory threadFactory = Executors.privilegedThreadFactory();
        //定義線程池
        //workQueue: 任務(wù)隊(duì)列
        //ArrayBlockingQueue:基于數(shù)組結(jié)構(gòu)的有界阻塞隊(duì)列,遵循FIFO原則
        //LinkedBlockingQueue:基于鏈表結(jié)構(gòu)的阻塞隊(duì)列蛤奥,遵循FIFO原則
        //SynchronousQueue:不存儲(chǔ)元素的阻塞隊(duì)列佳镜,每一個(gè)插入必須等到另一個(gè)線程調(diào)用移除操作,否則插入操作會(huì)一直處于阻塞狀態(tài)
        //PriorityBlockingQueue:具有優(yōu)先級(jí)的無限阻塞隊(duì)列
        //線程池pool的”corePoolSize”和”maximumPoolSize”分別為1和2凡桥,這意味著”線程池能同時(shí)運(yùn)行的任務(wù)數(shù)量最大是2蟀伸,LinkedBlockingQueue容量 設(shè)置為2,代表任務(wù)隊(duì)列只能有兩個(gè)任務(wù)阻塞等待
        //1. 線程進(jìn)入線程池后判斷執(zhí)行中的線程數(shù)量是否超過了corePoolSize唬血,超過了就將任務(wù)加入到任務(wù)隊(duì)列望蜡,沒超過新建線程執(zhí)行任務(wù)
        //2. 任務(wù)隊(duì)列容量滿了以后(僅限有界隊(duì)列),判斷執(zhí)行中的任務(wù)數(shù)是否超過了maximumPoolSize拷恨,沒超過創(chuàng)建新的線程繼續(xù)執(zhí)行,超過了根據(jù)飽和策略處理任務(wù)谢肾,例子中使用的是AbortPolicy腕侄,無法處理任務(wù)直接拋出異常
        ThreadPoolExecutor pool = new ThreadPoolExecutor(2, 2, 100, TimeUnit.SECONDS,
                new LinkedBlockingQueue<Runnable>(2), threadFactory) {
            //自定義beforeExecute和afterExecute方法
            @Override
            protected void beforeExecute(Thread t, Runnable r) {
                //System.out.println("任務(wù)執(zhí)行前調(diào)用");
            }

            @Override
            protected void afterExecute(Runnable r, Throwable t) {
                //System.out.println("任務(wù)執(zhí)行后調(diào)用");
            }
        };
        //提前創(chuàng)建并啟動(dòng)所有核心線程,使它們空閑地等待工作
        //預(yù)熱芦疏,任務(wù)來時(shí)可以直接執(zhí)行任務(wù)
        pool.prestartAllCoreThreads();
        //設(shè)置飽和策略
        //AbortPolicy 無法處理新任務(wù)時(shí)直接拋出異常
        //CallerRunsPolicy 直接在調(diào)用者的調(diào)用線程中運(yùn)行任務(wù)
        //DiscardOldestPolicy 丟棄最舊的未處理請(qǐng)求冕杠,并執(zhí)行當(dāng)前任務(wù)
        //DiscardPolicy 直接丟棄任務(wù)
        pool.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
        try {
            for (int i = 0; i < 5; i++) {
                //定義線程
                int finalI = i;
                Thread thread = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        System.out.println("第" + finalI + "線程執(zhí)行中");
                    }
                }, String.valueOf(i));
                //提交任務(wù)到線程池
                //execute 提交不需要返回值的任務(wù)
                //submit 提交需要返回值的任務(wù)
                //Future<?> future = pool.submit(thread);
                pool.execute(thread);
            }
        } catch (RejectedExecutionException e) {
            e.printStackTrace();
        } finally {
            //關(guān)閉線程,兩周方式
            //shutdownNow() 首先將線程池設(shè)置成stop狀態(tài)酸茴,然后嘗試停止所有正在執(zhí)行的任務(wù)分预,暫停正在等待的任務(wù),并返回正在等待執(zhí)行的任務(wù)的列表
            //shutdown() 將線程池設(shè)置成shutdown狀態(tài)薪捍,然后中斷所有沒有正在執(zhí)行的線程
            //List<Runnable> runnables = pool.shutdownNow();
            //pool.shutdown();
        }
    }

}

執(zhí)行結(jié)果

第0線程執(zhí)行中
第1線程執(zhí)行中
java.util.concurrent.RejectedExecutionException: Task Thread[4,5,main] rejected from com.sy.thread.example.ThreadPoolExecutorTest1$1@29453f44[Running, pool size = 2, active threads = 2, queued tasks = 2, completed tasks = 0]
    at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
    at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
    at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
    at com.sy.thread.example.ThreadPoolExecutorTest1.main(ThreadPoolExecutorTest1.java:62)
第2線程執(zhí)行中
第3線程執(zhí)行中

例子中的邏輯在注釋中稍微描述了一下笼痹,可以簡單看一下,只實(shí)現(xiàn)了一下基礎(chǔ)用法酪穿,ThreadPoolExecutor方法較多凳干,可以自己都試一下。

參考書籍《java并發(fā)編程的藝術(shù)》推薦大家閱讀被济。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末救赐,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子只磷,更是在濱河造成了極大的恐慌经磅,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,546評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件钮追,死亡現(xiàn)場離奇詭異预厌,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)畏陕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門配乓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事犹芹∑橐常” “怎么了?”我有些...
    開封第一講書人閱讀 164,911評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵腰埂,是天一觀的道長飒焦。 經(jīng)常有香客問我,道長屿笼,這世上最難降的妖魔是什么牺荠? 我笑而不...
    開封第一講書人閱讀 58,737評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮驴一,結(jié)果婚禮上休雌,老公的妹妹穿的比我還像新娘。我一直安慰自己肝断,他們只是感情好杈曲,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著胸懈,像睡著了一般担扑。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上趣钱,一...
    開封第一講書人閱讀 51,598評(píng)論 1 305
  • 那天涌献,我揣著相機(jī)與錄音,去河邊找鬼首有。 笑死燕垃,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的绞灼。 我是一名探鬼主播利术,決...
    沈念sama閱讀 40,338評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼低矮!你這毒婦竟也來了印叁?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,249評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤军掂,失蹤者是張志新(化名)和其女友劉穎轮蜕,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蝗锥,經(jīng)...
    沈念sama閱讀 45,696評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡跃洛,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了终议。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片汇竭。...
    茶點(diǎn)故事閱讀 40,013評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡葱蝗,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出细燎,到底是詐尸還是另有隱情两曼,我是刑警寧澤,帶...
    沈念sama閱讀 35,731評(píng)論 5 346
  • 正文 年R本政府宣布玻驻,位于F島的核電站悼凑,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏璧瞬。R本人自食惡果不足惜户辫,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望嗤锉。 院中可真熱鬧渔欢,春花似錦、人聲如沸档冬。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽酷誓。三九已至,卻和暖如春态坦,著一層夾襖步出監(jiān)牢的瞬間盐数,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評(píng)論 1 270
  • 我被黑心中介騙來泰國打工伞梯, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留玫氢,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,203評(píng)論 3 370
  • 正文 我出身青樓谜诫,卻偏偏與公主長得像漾峡,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子喻旷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評(píng)論 2 355