一、Executors建立執行緒池
總結
Java中建立執行緒池很簡單,只需要呼叫Executors
中相應的靜態方法即可,比如Executors.newFixedThreadPool(int nThreads)
,但是便捷不僅隱藏了複雜性,也為我們埋下了潛在的隱患(OOM,執行緒耗盡)。
Executors
建立執行緒池便捷方法列表:
方法名 | 功能 |
---|---|
newFixedThreadPool(int nThreads) | 建立固定大小的執行緒池 |
newSingleThreadExecutor() | 建立只有一個執行緒的執行緒池 |
newCachedThreadPool() | 建立一個不限執行緒數上限的執行緒池,任何提交的任務都將立即執行 |
使用注意事項:
1、小程式使用這些快捷方法沒什麼問題
2、對於服務端需要長期執行的程式,建立執行緒池應該直接使用ThreadPoolExecutor
的構造方法。上述Executors
底層實現也是ThreadPoolExecutor
。
-------------------------------------- 分 割 線 -----------------------------------------------------
1.FixedThreadPool 定長執行緒池
原始碼:
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }
根據原始碼可以看出:
- 該執行緒池的最大執行緒數等於核心執行緒數,所以在預設情況下,該執行緒池的執行緒不會因為閒置狀態超時而被銷燬。
- 如果當前執行緒數小於核心執行緒數,並且也有閒置執行緒的時候提交了任務,這時也不會去複用之前的閒置執行緒,會建立新的執行緒去執行任務。如果當前執行任務數大於了核心執行緒數,大於的部分就會進入佇列等待。等著有閒置的執行緒來執行這個任務。
建立方法:
//nThreads => 最大執行緒數即maximumPoolSize ExecutorService mFixedThreadPool= Executors.newFixedThreadPool(int nThreads);
//threadFactory => 建立執行緒的方法,用得少 ExecutorService mFixedThreadPool= Executors.newFixedThreadPool(int nThreads, ThreadFactory threadFactory);
用法:
private void startDownload(final ProgressBar progressBar, final int i) {
mFixedThreadPool.execute(new Runnable() {
@Override
public void run() {
//....邏輯程式碼自己控制
}
});
}
2.SingleThreadPool
原始碼:
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
根據原始碼可以看出:
- 有且僅有一個工作執行緒執行任務
- 所有任務按照指定順序執行,即遵循佇列的入隊出隊規則
建立方法: ExecutorService mSingleThreadPool = Executors.newSingleThreadPool();
用法同上。
3.可快取執行緒池CachedThreadPool()
原始碼:
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
根據原始碼可以看出:
- 這種執行緒池內部沒有核心執行緒,執行緒的數量是有沒限制的。
- 在建立任務時,若有空閒的執行緒時則複用空閒的執行緒,若沒有則新建執行緒。
- 沒有工作的執行緒(閒置狀態)在超過了60S還不做事,就會銷燬。
建立方法:
ExecutorService mCachedThreadPool = Executors.newCachedThreadPool();
用法:
//開始下載
private void startDownload(final ProgressBar progressBar, final int i) {
mCachedThreadPool.execute(new Runnable() {
@Override
public void run() {
int p = 0;
progressBar.setMax(10);//每個下載任務10秒
while (p < 10) {
p++;
progressBar.setProgress(p);
Bundle bundle = new Bundle();
Message message = new Message();
bundle.putInt("p", p);
//把當前執行緒的名字用handler讓textview顯示出來
bundle.putString("ThreadName", Thread.currentThread().getName());
message.what = i;
message.setData(bundle);
mHandler.sendMessage(message);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
}
4.ScheduledThreadPool
原始碼:
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
//ScheduledThreadPoolExecutor(): public ScheduledThreadPoolExecutor(int corePoolSize) { super(corePoolSize, Integer.MAX_VALUE, DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS, new DelayedWorkQueue()); }
根據原始碼可以看出: DEFAULT_KEEPALIVE_MILLIS就是預設10L,這裡就是10秒。這個執行緒池有點像是吧CachedThreadPool和FixedThreadPool 結合了一下。
- 不僅設定了核心執行緒數,最大執行緒數也是Integer.MAX_VALUE。
- 這個執行緒池是上述4箇中為唯一個有延遲執行和週期執行任務的執行緒池。
建立:
//nThreads => 最大執行緒數即maximumPoolSize
ExecutorService mScheduledThreadPool = Executors.newScheduledThreadPool(int corePoolSize);
一般的執行任務方法和上面的都大同小異,我們主要看看延時執行任務和週期執行任務的方法。
//表示在3秒之後開始執行我們的任務。
mScheduledThreadPool.schedule(new Runnable() {
@Override
public void run() {
//....
}
}, 3, TimeUnit.SECONDS);
//延遲3秒後執行任務,從開始執行任務這個時候開始計時,每7秒執行一次不管執行任務需要多長的時間。
mScheduledThreadPool.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
//....
}
},3, 7, TimeUnit.SECONDS);
/**延遲3秒後執行任務,從任務完成時這個時候開始計時,7秒後再執行,
*再等完成後計時7秒再執行也就是說這裡的迴圈執行任務的時間點是
*從上一個任務完成的時候。
*/
mScheduledThreadPool.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
//....
}
},3, 7, TimeUnit.SECONDS);
以上就是常用的四個執行緒池以及他們的實現原理。