寫作原因:Java或者Android開發(fā)者都知道,Java/Android中對于并發(fā)的控制是一個難點(diǎn)。如果控制不好線程問題,程序的穩(wěn)定性難以得到保障。下面博主分享一下Android中線程池機(jī)制的基本內(nèi)容。
原文鏈接:博主小屋
定義
這是Wikipedia對線程池的定義,看看即可:在計(jì)算機(jī)編程中,線程池包含一定數(shù)量的線程,這些線程用于并發(fā)地處理任務(wù)。通常情況下;反之,線程的數(shù)量根據(jù)可用的計(jì)算資源進(jìn)行調(diào)整從而達(dá)到合理地并行處理任務(wù)即使任務(wù)的數(shù)量取決于問題本身并且在處理之前并不知道它們的確切情況??床欢繘]關(guān)系,下面通過具體案例來學(xué)習(xí)使用。
優(yōu)勢
使用線程池有以下一些優(yōu)勢:
(1)最大程度合理地使用線程,從而減少線程創(chuàng)建與銷毀帶來的性能開銷。
(2)有效控制線程池的最大并發(fā)數(shù),避免大量線程之間因?yàn)榛ハ鄵屨枷到y(tǒng)資源而導(dǎo)致阻塞現(xiàn)象。
(3)能對線程進(jìn)行簡單的管理,并且提供定時(shí)執(zhí)行以及指定間隔循環(huán)執(zhí)行等功能。
ThreadPoolExecutor
下面先看看ThreadPoolExecutor
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory)
上面這段代碼正是構(gòu)成線程池的核心。Java幾乎所有線程池都是直接或者間接使用ThreadPoolExecutor來實(shí)現(xiàn)的,這里先講解一下這個線程池生成器的構(gòu)成和運(yùn)行模式,然后再講解一下其構(gòu)造方法相關(guān)形參的意義。
我個人把ThreadPoolExecutor理解成以下的模型,見下圖:
根據(jù)上面這個模型來理解構(gòu)造參數(shù)也就不難了。
int corePoolSize:設(shè)置核心線程的數(shù)量。
int maximumPoolSize:設(shè)置線程池最大線程容納量,當(dāng)活動線程數(shù)達(dá)到該值時(shí),后續(xù)新任務(wù)會被阻塞。
long keepAliveTime:設(shè)置非核心線程閑置的超時(shí)時(shí)長,當(dāng)allowCoreThreadTimeOut為True時(shí)同樣會影響到核心線程。
TimeUnit unit:指定KeepAliveTime參數(shù)的時(shí)間單位。
BlockingQueue<Runnable> workQueue:超額Runnable對象(參見模型圖)的儲存地。
ThreadFactory threadFactory:提供創(chuàng)建新線程的功能。
此外還有一個不常用的參數(shù)TejectedExecutionHandler handler,主要用于通知任務(wù)執(zhí)行失敗的情況,具體使用講解讀者自行學(xué)習(xí)。
ThreadPoolExecutor怎么執(zhí)行任務(wù)的呢?參見下面流程圖:

四大線程池
定義及模型
四大線程池的創(chuàng)建采用了靜態(tài)工廠模式(關(guān)于靜態(tài)工廠模式以后有相關(guān)的博文),我們來看看它們的定義及創(chuàng)建時(shí)關(guān)鍵的源碼,然后給出模型圖。
newCachedThreadPool創(chuàng)建一個可緩存線程池,如果線程池長度超過處理需要,可靈活回收空閑線程,若無可回收,則新建線程。
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
newFixedThreadPool 創(chuàng)建一個定長線程池,可控制線程最大并發(fā)數(shù),超出的線程會在隊(duì)列中等待。
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
newScheduledThreadPool 創(chuàng)建一個定長線程池,支持定時(shí)及周期性任務(wù)執(zhí)行。
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
newSingleThreadExecutor 創(chuàng)建一個單線程化的線程池,它只會用唯一的工作線程來執(zhí)行任務(wù),保證所有任務(wù)按照指定順序(FIFO, LIFO, 優(yōu)先級)執(zhí)行。
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
使用
對于使用方法直接在源碼中體現(xiàn),源碼已經(jīng)足夠通俗易懂,可以結(jié)合源碼及上面的定義模型分析學(xué)習(xí)。
public class ThreadPool {
private final static int SCHEDULED_DELAY = 0;
private final static int SCHEDULED_AT_FIXED_RATE = 1;
public static void main(String args[]){
startCachedThreadPool();
startFixedThreadPool();
startScheduledThreadPool(SCHEDULED_DELAY);
startScheduledThreadPool(SCHEDULED_AT_FIXED_RATE);
startSingleThreadExecutor();
}
private static void startCachedThreadPool(){
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
//可緩存的線程池
for(int i = 0;i<10;i++){
final int index = i;
try {
Thread.sleep(index * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
cachedThreadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println(index);
System.out.println("Thread's ID: "+Thread.currentThread().getId());
}
});
}
//線程池為無限大,當(dāng)執(zhí)行第二個任務(wù)時(shí)第一個任務(wù)已經(jīng)完成,會復(fù)用執(zhí)行第一個任務(wù)的線程,而不用每次新建線程。
}
private static void startScheduledThreadPool(int status){
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
switch(status){
case SCHEDULED_DELAY:
scheduledThreadPool.schedule(new Runnable() {
@Override
public void run() {
System.out.println("delay 3 seconds");
System.out.println("Thread's ID: "+Thread.currentThread().getId());
}
},3, TimeUnit.SECONDS);
break;
case SCHEDULED_AT_FIXED_RATE:
scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println("delay 1 seconds,and excute every 3 seconds");
System.out.println("Thread's ID: "+Thread.currentThread().getId());
}
},1,3,TimeUnit.SECONDS);
//不一定使用同一個線程來發(fā)送。
break;
}
}
private static void startFixedThreadPool(){
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
for(int i =0;i<10;i++){
final int index = i;
fixedThreadPool.execute(new Runnable() {
@Override
public void run() {
try {
System.out.println(index);
System.out.println("Thread's ID: "+Thread.currentThread().getId());
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
private static void startSingleThreadExecutor(){
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
for(int i = 0;i<10;i++){
final int index = i;
singleThreadExecutor.execute(new Runnable() {
@Override
public void run() {
try {
System.out.println(index);
System.out.println("Thread's ID: "+Thread.currentThread().getId());
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
}
總結(jié)
到此處博主大概梳理了一遍線程池的基本知識,如果有疏漏或者錯誤的地方求指正!