前言
1,線程池就是爲了避免系統頻繁的創建和銷燬線程,就像數據庫連接池類似。
2,jdk 已經提供了對線程值的支持。那就是Exeutor框架
一,Java線程池提供的幾種工廠方法
static ExecutorService |
newCachedThreadPool() 創建一個可根據需要創建新線程的線程池,但是在以前構造的線程可用時將重用它們。 |
static ExecutorService |
newFixedThreadPool(int nThreads) 創建一個可重用固定線程數的線程池,以共享的無界隊列方式來運行這些線程。 |
static ScheduledExecutorService |
newScheduledThreadPool(int corePoolSize) 創建一個線程池,它可安排在給定延遲後運行命令或者定期地執行。 |
static ExecutorService |
newSingleThreadExecutor() 創建一個使用單個 worker 線程的 Executor,以無界隊列方式來運行該線程。 |
static ScheduledExecutorService |
newSingleThreadScheduledExecutor() 創建一個單線程執行程序,它可安排在給定延遲後運行命令或者定期地執行。 |
區別:
1,第一個工程返回一個可根據實際情況調整線程熟練的線程池,當線程有空閒的,新的任務添加時,就會複用線程,如果沒有空閒線程,那麼就會創建新的線程處理任務,如果任務過多,那麼就會導致OOM。
內部實現:
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
2,第二個方法返回一個固定大小的線程池,也就是說線程持中的線程數保持不變,當又新的任務添加時,如果沒有線程可供複用,就會把這個任務添加到任務隊列,
內部實現:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
3,第三個方法返回一個ScheduleExecutorService對象 ,這個線程池是按照一定週期去執行任務的。
public static ScheduledExecutorService newScheduledThreadPool(
int corePoolSize, ThreadFactory threadFactory) {
return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
}
4,第四個返回一個只有一個線程的線程池,多餘的任務會被提交到任務隊列。
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
5,第五個和第三個類似。但線程大小隻有一個
public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
return new DelegatedScheduledExecutorService
(new ScheduledThreadPoolExecutor(1));
}
可以看出:除了創建有計劃時間的線程池,其他的內部都是使用了
public ThreadPoolExecutor(int corePoolSize,//指定線程池中線程的數量
int maximumPoolSize,//制定線程池中最大的線程數量
long keepAliveTime,//多餘線程的存活時間
TimeUnit unit,//存活時間的單位
BlockingQueue<Runnable> workQueue,//違背執行的任務隊列
ThreadFactory threadFactory,//線程工廠
RejectedExecutionHandler handler)//拒絕策略
)
這個構造方法的關鍵參數就是阻塞隊列的不同實現,從而導致不同線程池的不同功能,以及使用技巧。
二,阻塞隊列的區別:
1,直接提交隊列,SynchronousQueue,該隊列沒有容量,每一個插入操作都會等待一個刪除操作。提交的任務不會被真實的保存,總是新的任務 提交個線程執行,沒有空閒,就會創建新的線程,那麼使用該隊列所創的線程池,當進程數量達到最大值,就會採取拒絕策略,若不想這樣的情況,就要設置很大的線程數,那麼就會導致OOM。
2,有界的任務隊列,ArrayBlockingQueue,使用該隊列創建的線程池,判斷規則如下:
3,無界的任務隊列:LinkedBlockingQueue,相比於有界,如果實際線程數到達了corepoolSize,還有新的任務提交,就會被添加到隊列中,直到系統資源耗盡,,該方法可能會導致OOM,
4,優先級隊列,PriorityBlockingQueue,根據任務自身的優先級順序先後執行。
所以在創建線程池的時候,儘量不要直接使用Executors的工廠方法,而是使用ExecutorPoolService()的構造方法,根據需求定製參數,這樣使用線程池,更爲直觀。
ExecutorService executorService = new ThreadPoolExecutor(5,5,0L, TimeUnit.SECONDS,new LinkedBlockingDeque<Runnable>(),new RejectedExecutionHandler());
參考《Java高併發程序設計》