執行緒精進指南之執行緒池進階
為什麼引進執行緒池
魚池,我們可以釣出來一條再放回去,釣出來一條再放回去,這樣來撩魚。
那執行緒池該如何玩呢?對,取出來一“條”執行緒,用完後再扔回去,再取出來,再扔....
執行緒池的優點:
避免大量的建立和銷燬帶來的效能開銷
避免大量的執行緒間因互相搶佔系統資源導致的阻塞現象。
能夠對執行緒進行簡單的管理並提供定時執行、間隔執行等功能。
缺點
佔用一定的記憶體空間。
執行緒越多CPU的排程開銷越大。
程式的複雜度會上升。
執行緒池的基本使用
使用執行緒池 ,肯定要對“池”進行配置,像基本的池多大啊,能容納多少魚啊,等這些是需要建造前就要確定的,因此我們搞池之前先設計
• int corePoolSize
無論是閒置還是工作中,永遠都不會銷燬的執行緒,會一直線上程池中存在,那我們是不是永遠都奈何不了它呢,當然不會,把ThreadPoolExecutor的allowCoreThreadTimeOut這個屬性設定為true,超過規定時長也會銷燬
• int maximumPoolSize 執行緒總數最大值
就是我們所有的執行緒啊,對,包括非核心的和上邊講的核心的
• long keepAliveTime
如果不是核心執行緒,超過這個引數的時間就會被幹掉
• TimeUnit unit
時間總是有單位的吧,對就是上邊KeepAliveTime的時間引數哇
型別時列舉,這裡舉幾種常用的,反正說多了也記不住,需要時候
SECONDS : 秒
MINUTES : 分
HOURS : 小時
DAYS : 天
• BlockingQueue workQueue
佇列內容較多,我們下邊單獨講
• ThreadFactory threadFactory
這個一般不用,沒必要管啦
• RejectedExecutionHandler handler
如果執行的過程中,拋異常了,我們可以用這個來指定,但是系統有預設的,因此這個也可以不用
使用執行緒池當然離不開Executor這個介面,具體的實現類在ThreadPoolExecutor中,so我們簡單瞭解下這個類
//對,使用的就是這幾個構造,引數我們上邊已經將過了
public class ThreadPoolExecutor extends AbstractExecutorService {
.....
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable>
workQueue);
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable>
workQueue,ThreadFactory threadFactory);
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable>
workQueue,RejectedExecutionHandler handler);
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable>
workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler);
...
}
常用的幾種執行緒池
執行緒都池都是是使用Executors這個類創建出來的
• CachedThreadPool()
可快取執行緒池:
執行緒數無限制
優先使用空閒執行緒,如果沒有才新建執行緒
//建立方式
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
//原始碼中的定義
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
• FixedThreadPool()
固定長度的執行緒池
可以控制執行緒的數量
如果超過則必須排隊執行
//建立方式
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(執行緒數量);
//原始碼中的定義
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
• ScheduledThreadPool()
對,就是它可以定時
//建立方法
ExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(最大執行緒數);
//原始碼中的定義
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
{
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE,
DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
new DelayedWorkQueue());
}
• SingleThreadExecutor()
所有任務排隊執行,一次只能執行一個任務
//建立方法
ExecutorService singleThreadPool = Executors.newSingleThreadPool();
//原始碼中的定義
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1,
1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
佇列
佇列類似我們的集合,實現了Collection介面
佇列中排隊執行的是我們runnable物件
常用的佇列有如下幾種
• SynchronousQueue:
有任務來就執行交給空閒執行緒,如果沒有就新建執行緒執行,so 執行緒數設定儘可能大即Integer.MAX_VALUE
• LinkedBlockingQueue:
永遠在核心執行緒內使用執行緒,如果超過了核心的執行緒就在佇列中等待執行
• ArrayBlockingQueue:
優先使用核心執行緒數,其次使用非核心的,如果用完了就進入佇列等待
• DelayQueue:
想進入佇列必須實現Delayed介面,達到指定時間後,方可執行任務