?來源:?blog.csdn.net/dabusiGin/article/details/105327873/
Executor是不建議的
Executors類為我們提供了各種型別的執行緒池,經常使用的工廠方法有:
public static ExecutorService newSingleThreadExecutor()
public static ExecutorService newFixedThreadPool(int nThreads)
public static ExecutorService newCachedThreadPool()
public static ScheduledExecutorService newSingleThreadScheduledExecutor()
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
書寫一段很簡單的測驗代碼:
public class ThreadDemo {
public static void main(String[] args) {
ExecutorService es = Executors.newSingleThreadExecutor();
}
}
當我們用阿里巴巴的P3C檢查代碼時,會被教育的!!!!

阿里爸爸是不允許這么創建執行緒池的,上面的警告寫的很明確“執行緒池不允許使用Executors去創建,而是通過ThreadPoolExecutor的方式,這樣的處理方式讓寫的同學更加明確執行緒池的運行規則,規避資源耗盡的風險,”(PS:很難得在編譯器中看到中文提示,對于英語不好的同學來說,簡直是福音,喜極而泣!!!!)
強制使用ThreadPoolExecutor
我們使用ThreadPoolExecutor創建執行緒池:
public class ThreadDemo {
public static void main(String[] args) {
ExecutorService es = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(10), Executors.defaultThreadFactory(),
new ThreadPoolExecutor.DiscardPolicy());
}
}
此時,再用P3C檢查代碼,終于沒有報錯了,
在華麗的分隔符之后,我們還是有必要從JDK原始碼的層面深挖一下其中的原理,
首先是靜態方法newSingleThreadExecutor()、newFixedThreadPool(int nThreads)、newCachedThreadPool(),我們來看一下其原始碼實作(基于JDK8),
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
通過查看原始碼我們知道上述三種靜態方法的內部實作均使用了ThreadPoolExecutor類,難怪阿里爸爸會建議通過ThreadPoolExecutor的方式實作,原來Executors類的靜態方法也是用的它,只不過幫我們配了一些引數而已,
第二是ThreadPoolExecutor類的構造方法,既然現在要直接使用ThreadPoolExecutor類了,那么其中的初始化引數就要我們自己配了,了解其構造方法勢在必行,
ThreadPoolExecutor類一共有四個構造方法,我們只需要了解之中的一個就可以了,因為其他三種構造方法只是幫我們配置了一些默認引數,最后還是呼叫了它,
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
其中的引數含義是:
corePoolSize:執行緒池中的執行緒數量;maximumPoolSize:執行緒池中的最大執行緒數量;keepAliveTime:當執行緒池執行緒數量超過corePoolSize時,多余的空閑執行緒會在多長時間內被銷毀;unit:keepAliveTime的時間單位;workQueue:任務佇列,被提交但是尚未被執行的任務;threadFactory:執行緒工廠,用于創建執行緒,一般情況下使用默認的,即Executors類的靜態方法defaultThreadFactory();handler:拒絕策略,當任務太多來不及處理時,如何拒絕任務,
對于這些引數要有以下了解:
corePoolSize與maximumPoolSize的關系
首先corePoolSize肯定是 <= maximumPoolSize,
其他關系如下:
- 若當前執行緒池中執行緒數 < corePoolSize,則每來一個任務就創建一個執行緒去執行;
- 若當前執行緒池中執行緒數 >= corePoolSize,會嘗試將任務添加到任務佇列,如果添加成功,則任務會等待空閑執行緒將其取出并執行;
- 若佇列已滿,且當前執行緒池中執行緒數 < maximumPoolSize,創建新的執行緒;
- 若當前執行緒池中執行緒數 >= maximumPoolSize,則會采用拒絕策略(JDK提供了四種,下面會介紹到),
注意:關系3是針對的有界佇列,無界佇列永遠都不會滿,所以只有前2種關系,
workQueue
引數workQueue是指提交但未執行的任務佇列,若當前執行緒池中執行緒數>=corePoolSize時,就會嘗試將任務添加到任務佇列中,主要有以下幾種:
SynchronousQueue:直接提交佇列,SynchronousQueue沒有容量,所以實際上提交的任務不會被添加到任務佇列,總是將新任務提交給執行緒執行,如果沒有空閑的執行緒,則嘗試創建新的執行緒,如果執行緒數量已經達到最大值(maximumPoolSize),則執行拒絕策略,LinkedBlockingQueue:無界的任務佇列,當有新的任務來到時,若系統的執行緒數小于corePoolSize,執行緒池會創建新的執行緒執行任務;當系統的執行緒數量等于corePoolSize后,因為是無界的任務佇列,總是能成功將任務添加到任務佇列中,所以執行緒數量不再增加,若任務創建的速度遠大于任務處理的速度,無界佇列會快速增長,直到記憶體耗盡,
handler
JDK內置了四種拒絕策略:
DiscardOldestPolicy策略:丟棄任務佇列中最早添加的任務,并嘗試提交當前任務;CallerRunsPolicy策略:呼叫主執行緒執行被拒絕的任務,這提供了一種簡單的反饋控制機制,將降低新任務的提交速度,DiscardPolicy策略:默默丟棄無法處理的任務,不予任何處理,AbortPolicy策略:直接拋出例外,阻止系統正常作業,
至此,我們直接new ThreadPoolExecutor類就不用慌了!!!!
近期熱文推薦:
1.1,000+ 道 Java面試題及答案整理(2022最新版)
2.勁爆!Java 協程要來了,,,
3.Spring Boot 2.x 教程,太全了!
4.別再寫滿屏的爆爆爆炸類了,試試裝飾器模式,這才是優雅的方式!!
5.《Java開發手冊(嵩山版)》最新發布,速速下載!
覺得不錯,別忘了隨手點贊+轉發哦!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/491984.html
標籤:Java
上一篇:Mysql索引-B+樹
