線程池作用
借由《Java并發(fā)編程的藝術(shù)》
- 降低資源消耗。通過重復(fù)利用已經(jīng)創(chuàng)建的線程,能夠降低線程創(chuàng)建和銷毀造成的消耗。
- 提高響應(yīng)速度。當(dāng)任務(wù)到達(dá)時,任務(wù)可以不需要等待線程的創(chuàng)建就能立即執(zhí)行。
- 提高線程的可管理性。線程是稀缺資源,如果無限制地創(chuàng)建,不僅會消耗系統(tǒng)資源,還會降低系統(tǒng)的穩(wěn)定性,使用線程池可以進(jìn)行統(tǒng)一的分配,調(diào)優(yōu)和監(jiān)控。
ThreadPoolExecutor類
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
...
}
ThreadPoolExecutor構(gòu)造
ThreadPoolExecutor類的構(gòu)造參數(shù):
-
corePoolSize:核心線程數(shù)量,初始化就創(chuàng)建的線程,沒有任務(wù)也不會被關(guān)閉的線程。也會有例外,如:allowCoreThreadTimeOut設(shè)置為true時,會被關(guān)閉。 -
maximumPoolSize:最大線程數(shù)量。 -
keepAliveTime:空閑線程的存活時間,超時后線程會被關(guān)閉,核心線程除外。 -
unit:空閑時間單位,一般使用TimeUnit枚舉 -
workQueue:工作隊列,當(dāng)所有線程都被占用后,新的任務(wù)就會被放在工作隊列中。 -
threadFactory:線程工廠。 -
handler:飽和策略,用于線程池中沒有空閑線程可以使用且工作列也處于飽和狀態(tài)時執(zhí)行的拒絕策略。
常用的拒絕策略
-
AbortPolicy:拋出RejectedExecutionException異常拒絕新的任務(wù)處理,默認(rèn)拒絕策略。 -
CallerRunsPolicy:如果程序關(guān)閉,會丟掉任務(wù)。此策略提供簡單的反饋控制機(jī)制,能夠減緩新任務(wù)的提交速度,但會造成延遲。如果項目可以承受延遲且不能丟棄任何一個任務(wù)請求,可以使用此策略。 -
DiscardPolicy:不處理新任務(wù),直接丟掉。 -
DiscardOldestPolicy:丟失最早的未處理的任務(wù)。
ThreadPoolExecutor線程狀態(tài)
-
RUNNING:接收新的任務(wù)和處理隊列中的任務(wù) -
SHUTDOWN:不能新增任務(wù),但是會繼續(xù)處理已經(jīng)添加的任務(wù) -
STOP:不能新增任務(wù),不會繼續(xù)處理已經(jīng)添加任務(wù) -
TIDYING:所有的任務(wù)已經(jīng)被終止,工作線程為0 -
TERMINATED:terminated()方法執(zhí)行完成
創(chuàng)建線程池
創(chuàng)建Runnable接口實現(xiàn)類
public class MyThread implements Runnable {
private String taskName;
public MyThread(String taskName) {
this.taskName = taskName;
}
@Override
public void run() {
try {
String threadName = Thread.currentThread().getName();
System.out.println("線程 " + threadName + " 開始執(zhí)行:" + taskName);
Thread.sleep(3000);
System.out.println("線程 " + threadName + " 開始執(zhí)行:" + taskName);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public String toString() {
return "MyThread{" +
"taskName='" + taskName + '\'' +
'}';
}
}
使用ThreadPoolExecutor創(chuàng)建
public static void main(String[] args) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(
// 核心線程數(shù)
5,
// 最大線程數(shù)
10,
// 等待時間
100,
// 等待時間單位 秒
TimeUnit.SECONDS,
// 任務(wù)隊列 容量100
new ArrayBlockingQueue<>(100),
// 飽和策略
new ThreadPoolExecutor.CallerRunsPolicy()
);
for (int i = 1; i <= 10; i++) {
MyThread myThread = new MyThread("任務(wù)" + i);
executor.execute(myThread);
}
executor.shutdown();
}
幾種常見的線程池
固定線程池(FixThreadPool)
線程池中的固定數(shù)量線程可以重復(fù)使用
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory);
}
創(chuàng)建方法:
ExecutorService executor = Executors.newFixedThreadPool(5);
for (int i = 1; i <= 10; i++) {
MyThread myThread = new MyThread("任務(wù)" + i);
executor.execute(myThread);
}
- 當(dāng)前運(yùn)行的線程數(shù)小于
coreSize的時候,有新任務(wù)就創(chuàng)建線程來執(zhí)行。 - 當(dāng)前運(yùn)行的線程數(shù)等于
coreSize的時候,有新任務(wù)將會追加到LinkedBlockingQueue隊列中。 - 線程池中的線程執(zhí)行完后,會循環(huán)從LinkedBlockingQueue中獲取任務(wù)執(zhí)行。
需要注意的是,LinkedBlockingQueue是一個無界隊列,它的容量為:
Integer.MAX_VALUE,也就是說,當(dāng)所有線程被占用后,新的任務(wù)將會無限堆加到這個隊列中,如果任務(wù)較多,可能會出現(xiàn)OOM現(xiàn)象。
單一線程池(SingleThreadExecutor)
只有一個線程,空閑也不會被關(guān)閉。
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
創(chuàng)建方法:
ExecutorService executor = Executors.newSingleThreadExecutor();
for (int i = 1; i <= 10; i++) {
MyThread myThread = new MyThread("任務(wù)" + i);
executor.execute(myThread);
}
緩存線程池(CachedThreadPool)
線程數(shù)量為
Integer.MAX_VALUE,空閑線程會被臨時緩存60s,沒有任務(wù)分配會關(guān)閉。如果提交任務(wù)速度過快,也一樣可能會出現(xiàn)OOM現(xiàn)象。
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
創(chuàng)建方法:
ExecutorService executor = Executors.newCachedThreadPool();
for (int i = 1; i <= 10; i++) {
MyThread myThread = new MyThread("任務(wù)" + i);
executor.execute(myThread);
}
原文發(fā)布在:傳送門