線程池的優(yōu)點(diǎn):
- 重用線程池中的線程,避免因?yàn)榫€程的創(chuàng)建和銷毀帶來的性能消耗
- 能有效的控制線程的最大并發(fā)數(shù),避免大量的線程之間因搶占系統(tǒng)資源而導(dǎo)致的阻塞現(xiàn)象
- 能夠?qū)€程進(jìn)行簡單的管理,并提供定時(shí)執(zhí)行以及指定間隔循環(huán)執(zhí)行等功能
ThreadPoolExecutor:
Android中,用ThreadPoolExecutor來實(shí)現(xiàn)線程池的配置。
ThreadPoolExecutor文檔中文版
ThreadPoolExecutor文檔英文版
ThreadPoolExecutor的構(gòu)造方法
ThreadPoolExecutor的構(gòu)造方法有四個(gè),其實(shí)現(xiàn)如下:
```
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
TimeUnit unit, BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
TimeUnit unit, BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
TimeUnit unit, BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
}
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
TimeUnit unit,BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory, RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
```
構(gòu)造方法的參數(shù)
corePoolSize
程池中的核心線程數(shù),也就是是線程池中的最小線程數(shù);
核心線程在allowCoreThreadTimeout被設(shè)置為true時(shí)會(huì)超時(shí)退出,默認(rèn)情況下不會(huì)退出;maximumPoolSize
最大線程池大小,當(dāng)活動(dòng)線程數(shù)達(dá)到這個(gè)值,后續(xù)任務(wù)會(huì)被阻塞keepAliveTime
線程池中超過corePoolSize數(shù)目的非核心線程最大存活時(shí)間;閑置時(shí)的超時(shí)時(shí)長,超過這個(gè)值后,閑置線程就會(huì)被回收unit
keepAliveTime 參數(shù)的時(shí)間單位。這是一個(gè)枚舉,詳情請(qǐng)參考TimeUnitworkQueue
執(zhí)行前用于保持任務(wù)的隊(duì)列,也就是線程池的緩存隊(duì)列。此隊(duì)列僅保持由 execute 方法提交的 Runnable 任務(wù)
關(guān)于三種提交策略這篇文章不錯(cuò)threadFactory
線程工廠,為線程池提供創(chuàng)建新線程的功能,它是一個(gè)接口,只有一個(gè)方法:Thread newThread(Runnable r)
-
RejectedExecutionHandler
線程池對(duì)拒絕任務(wù)的處理策略。一般是隊(duì)列已滿或者無法成功執(zhí)行任務(wù),這時(shí)ThreadPoolExecutor會(huì)調(diào)用handler的rejectedExecution方法來通知調(diào)用者
ThreadPoolExecutor默認(rèn)有四個(gè)拒絕策略:1、ThreadPoolExecutor.AbortPolicy() 直接拋出異常RejectedExecutionException 2、ThreadPoolExecutor.CallerRunsPolicy() 直接調(diào)用run方法并且阻塞執(zhí)行 3、ThreadPoolExecutor.DiscardPolicy() 直接丟棄后來的任務(wù) 4、ThreadPoolExecutor.DiscardOldestPolicy() 丟棄在隊(duì)列中隊(duì)首的任務(wù)
也可以自己繼承RejectedExecutionHandler來寫拒絕策略.
ThreadPoolExecutor的執(zhí)行過程:
一個(gè)任務(wù)通過 execute(Runnable)方法被添加到線程池,任務(wù)就是一個(gè) Runnable類型的對(duì)象,任務(wù)的執(zhí)行方法就是Runnable類型對(duì)象的run()方法。
- 當(dāng)線程池小于corePoolSize時(shí),新提交任務(wù)將創(chuàng)建一個(gè)新線程執(zhí)行任務(wù),即使此時(shí)線程池中存在空閑線程
- 當(dāng)線程池達(dá)到corePoolSize時(shí),新提交任務(wù)將被放入workQueue中,等待線程池中任務(wù)調(diào)度執(zhí)行
- 當(dāng)提交任務(wù)數(shù)超過【maximumPoolSize+阻塞隊(duì)列大小】時(shí),新提交任務(wù)由RejectedExecutionHandler處理 (關(guān)于這里,網(wǎng)上90%以上的人說當(dāng)任務(wù)數(shù)>=maximumPoolSize時(shí)就會(huì)被拒絕,我不知道依據(jù)在哪里,也不知道代碼驗(yàn)證過沒,經(jīng)過我的驗(yàn)證這種說法是不成立的,具體的看下邊日志分析)
- 當(dāng)線程池中超過corePoolSize線程,空閑時(shí)間達(dá)到keepAliveTime時(shí),關(guān)閉空閑線程
- 當(dāng)設(shè)置allowCoreThreadTimeOut(true)時(shí),線程池中corePoolSize線程空閑時(shí)間達(dá)到keepAliveTime也將關(guān)閉
定制自己的線程池:
public class ThreadTestActivity extends AppCompatActivity {
private final int CORE_POOL_SIZE = 1;//核心線程數(shù)
private final int MAX_POOL_SIZE = 3;//最大線程數(shù)
private final int BLOCK_SIZE = 2;//阻塞隊(duì)列大小
private final long KEEP_ALIVE_TIME = 2;//空閑線程超時(shí)時(shí)間
private ThreadPoolExecutor executorPool;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_thread_test);
//創(chuàng)建線程池
// 創(chuàng)建一個(gè)核心線程數(shù)為3、最大線程數(shù)為8,緩存隊(duì)列大小為5的線程池
executorPool = new ThreadPoolExecutor(CORE_POOL_SIZE, MAX_POOL_SIZE, KEEP_ALIVE_TIME,
TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(BLOCK_SIZE),
Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
executorPool.allowCoreThreadTimeOut(true);
}
public void begin(View view) {
for (int num = 0; num < 6; num++) {//每個(gè)500ms添加一個(gè)任務(wù)到隊(duì)列中
try {
Li("execute");// 監(jiān)聽相關(guān)數(shù)據(jù)
executorPool.execute(new WorkerThread("thread-" + num));
} catch (Exception e) {
Log.e("threadtest", "AbortPolicy...");
}
}
// 20s后,所有任務(wù)已經(jīng)執(zhí)行完畢,我們?cè)诒O(jiān)聽一下相關(guān)數(shù)據(jù)
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(20 * 1000);
} catch (Exception e) {
}
Li("monitor after");
}
}).start();
}
private void Li(String mess) {
Log.i("threadtest", "monitor " + mess
+ " CorePoolSize:" + executorPool.getCorePoolSize()
+ " PoolSize:" + executorPool.getPoolSize()
+ " MaximumPoolSize:" + executorPool.getMaximumPoolSize()
+ " ActiveCount:" + executorPool.getActiveCount()
+ " TaskCount:" + executorPool.getTaskCount()
);
}
}
// 模擬耗時(shí)任務(wù)
public class WorkerThread implements Runnable {
private String threadName;
public WorkerThread(String threadName) {
this.threadName = threadName;
}
@Override
public synchronized void run() {
int i = 0;
boolean flag = true;
try {
while (flag) {
Thread.sleep(1000);
i++;
Log.e("threadtest", "WorkerThread " + threadName + " " + i);
if (i >2) flag = false;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public String getThreadName() {
return threadName;
}
}
日志信息:
下面就來對(duì)日志信息進(jìn)行分析:
- 上邊粉色部分(1~6行),可以看到poolsize逐漸累加,一直加到最大線程數(shù)后不再增加,這呼應(yīng)了上述“執(zhí)行過程1”
- 接下來綠色部分()7行,驗(yàn)證了上邊我們說的“執(zhí)行過程3”,緩存隊(duì)列數(shù)為2,最大線程數(shù)為3,共有6條任務(wù),所以會(huì)有【 6-(2+3)】條任務(wù)被拒絕,這里拒絕策略我們用的是
ThreadPoolExecutor.AbortPolicy()
也就是直接拋出異常,也就是我們?nèi)罩镜牡?行 - 然后8~22行是任務(wù)的執(zhí)行過程,
- 其中藍(lán)色部分(8~16)行,我們可以看到有3條任務(wù)在同時(shí)執(zhí)行,也就是最大線程數(shù)
- 接下來的綠色(17~22行),在三條任務(wù)執(zhí)行完成后,剩余的排隊(duì)任務(wù)才開始執(zhí)行
- 最后,23行,20s后,線程都處于空閑狀態(tài),所以非核心線程會(huì)被回收,但是因?yàn)榇a中我們?cè)O(shè)置了
executorPool.allowCoreThreadTimeOut(true)
,所以這時(shí)處于空閑狀態(tài)的核心線程也會(huì)被回收,這時(shí)池中的線程數(shù)為0
關(guān)于線程池的一些建議
- 最大線程數(shù)一般設(shè)為2N+1最好,N是CPU核數(shù)
官方定義的四種線程池
其實(shí),本應(yīng)該先說官方定義的這四種線程池,然后再說自定義線程池,但是考慮到里邊的一些配置參數(shù),所以本帖先利用自定義線程池把各個(gè)配置參數(shù)理一下,然后再講官方定義的四種線程池,這樣也便于理解官方定義的這四種線程池
這四種線程池都是通過Executors的工廠方法來實(shí)現(xiàn)
1、FixedThreadPool
他是一種數(shù)量固定的線程池,且任務(wù)隊(duì)列也沒有大小限制;
它只有核心線程,且這里的核心線程也沒有超時(shí)限制,所以即使線程處于空閑狀態(tài)也不會(huì)被回收,除非線程池關(guān)閉;
當(dāng)所有的任務(wù)處于活動(dòng)狀態(tài),新任務(wù)都處于等待狀態(tài),知道所有線程空閑出來;
因?yàn)樗粫?huì)被回收,所以它能更快的響應(yīng);
源碼:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
實(shí)現(xiàn):
ExecutorService service = Executors.newFixedThreadPool(3);
service.execute(new WorkerThread("thread-" + num));
2、CachedThreadPool
無界線程池,可以進(jìn)行自動(dòng)線程回收
他是一種線程數(shù)量不固定的線程池;
它只有非核心線程,且最大線程數(shù)為Integer.MAX_VALUE,也就是說線程數(shù)可以任意大;
當(dāng)池中的線程都處于活動(dòng)狀態(tài)時(shí),會(huì)創(chuàng)建新的線程來處理任務(wù),否則會(huì)利用空閑線程來處理任務(wù);所以,任何添加進(jìn)來的任務(wù)都會(huì)被立即執(zhí)行;
池中的空閑線程都有超時(shí)限制,為60s,超過這個(gè)限制就會(huì)被回收,當(dāng)池中的所有線程都處于閑置狀態(tài)時(shí),都會(huì)因超時(shí)而被回收,這個(gè)時(shí)候,她幾乎不占用任何系統(tǒng)資源;
適合做大量的耗時(shí)較少的任務(wù);
源碼:
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
實(shí)現(xiàn):
ExecutorService service = Executors.newCachedThreadPool();
service.execute(new WorkerThread("thread-"));
3、SingleThreadExecutor
只有一個(gè)核心線程,所有任務(wù)都在同一線程中按序執(zhí)行,這樣也就不需要處理線程同步的問題;
源碼:
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
實(shí)現(xiàn):
ExecutorService service = Executors.newSingleThreadExecutor();
service.execute(new WorkerThread("thread-"));
4、ScheduledThreadPool
它的核心線程數(shù)量是固定的,而非核心線程是沒有限制的,且非核心線程空閑時(shí)會(huì)被回收;
適合執(zhí)行定時(shí)任務(wù)和具有固定周期的任務(wù)
源碼:
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
return new DelegatedScheduledExecutorService
(new ScheduledThreadPoolExecutor(1));
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE,
DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
new DelayedWorkQueue());
}
實(shí)現(xiàn):
ScheduledExecutorService pool = Executors.newScheduledThreadPool(2);
或
ScheduledExecutorService pool = Executors.newSingleThreadScheduledExecutor();
threadPool.schedule(runnable, 20, TimeUnit.SECONDS);// 20秒后執(zhí)行任務(wù)
或
threadPool.scheduleAtFixedRate(runnable,10,20,TimeUnit.SECONDS);//延遲10s,每20s執(zhí)行一次任務(wù)
由于本人技術(shù)有限,避免不了出現(xiàn)一些錯(cuò)誤或者理解有偏差描述不清楚的地方,請(qǐng)大家諒解并提醒我:)
上一篇:AsyncTask
再來一篇:java中的thread
更多內(nèi)容請(qǐng)關(guān)注我的Android專題
本文出自:http://www.lxweimin.com/users/c1b4a5542220/latest_articles
轉(zhuǎn)載請(qǐng)注明出處!