使用線程池的好處
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()
等等
線程池處理流程
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ù)示意圖
- 任務(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ù)》推薦大家閱讀被济。