工作中禁止使用Executors快捷創(chuàng)建線程池原理詳解
問題?
在很多公司(如阿里、華為等)的編程規(guī)范中,非常明確地禁止使用Executors快捷創(chuàng)建線程池,為什么呢?這里從源碼講起,介紹使用Executors工廠方法快捷創(chuàng)建線程池將會面臨的潛在問題。


1.1 newFixedThreadPool的潛在問題
基本使用
// 線程池
ExecutorService singleThreadExecutor = Executors.newFixedThreadPool(2);
// 批量添加線程
for (int i = 0; i < 7; i++) {
singleThreadExecutor.execute(new TargetTask());
// singleThreadExecutor.submit(new TargetTask());
}
Thread.sleep(1000);
// 線程池銷毀
singleThreadExecutor.shutdown();;
查看源碼
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
/**
* Creates a {@code LinkedBlockingQueue} with a capacity of
* {@link Integer#MAX_VALUE}.
*/
public LinkedBlockingQueue() {
this(Integer.MAX_VALUE);
}
我們可以看出:
- corePoolSize(核心線程數(shù))=maximumPoolSize(最大線程數(shù))。
- LinkedBlockingQueue是一個無界隊列,如果提交的任務過快會造成任務大量的的堆積,消耗完服務器資源。
- 如果隊列很大,很有可能導致JVM出現(xiàn)OOM(Out Of Memory)異常,即內(nèi)存資源耗盡。
1.2 newSingleThreadExecutor的潛在問題?
基本使用
// 線程池
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
// 批量添加線程
for (int i = 0; i < 5; i++) {
singleThreadExecutor.execute(new TargetTask());
// singleThreadExecutor.submit(new TargetTask());
}
Thread.sleep(1000);
// 線程池銷毀
singleThreadExecutor.shutdown();;
查看源碼
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
/**
* Creates a {@code LinkedBlockingQueue} with a capacity of
* {@link Integer#MAX_VALUE}.
*/
public LinkedBlockingQueue() {
this(Integer.MAX_VALUE);
}
嘗試修改核心線程數(shù)
package ExecutorDemo.newSingleThreadExecutor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
/**
* @description:
* @author: shu
* @createDate: 2022/11/1 10:45
* @version: 1.0
*/
public class UpdateSingleThreadExecutor {
public static void main(String[] args) {
//創(chuàng)建一個固定大小的線程池
ExecutorService fixedExecutorService =
Executors.newFixedThreadPool(1);
ThreadPoolExecutor threadPoolExecutor =
(ThreadPoolExecutor) fixedExecutorService;
System.out.println(threadPoolExecutor.getMaximumPoolSize());
//設置核心線程數(shù)
threadPoolExecutor.setCorePoolSize(8);
//創(chuàng)建一個單線程化的線程池
ExecutorService singleExecutorService =
Executors.newSingleThreadExecutor();
//轉(zhuǎn)換成普通線程池,會拋出運行時異常 java.lang.ClassCastException
((ThreadPoolExecutor) singleExecutorService).setCorePoolSize(8);
}
}
我們可以看出:
- 單例存在,我們無法去修改核心線程數(shù),否則會造成異常處理。
- corePoolSize(核心線程數(shù))=maximumPoolSize(最大線程數(shù))=1 。
- LinkedBlockingQueue是一個無界隊列,如果提交的任務過快會造成任務大量的的堆積,消耗完服務器資源。
- 如果隊列很大,很有可能導致JVM出現(xiàn)OOM(Out Of Memory)異常,即內(nèi)存資源耗盡。
1.3 newCachedThreadPool的潛在問題
基本使用
// 線程池
ExecutorService singleThreadExecutor = Executors.newCachedThreadPool();
// 批量添加線程
for (int i = 0; i < 7; i++) {
singleThreadExecutor.execute(new TargetTask());
// singleThreadExecutor.submit(new TargetTask());
}
Thread.sleep(1000);
// 線程池銷毀
singleThreadExecutor.shutdown();;
源碼分析
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
* Creates a {@code SynchronousQueue} with nonfair access policy.
*/
public SynchronousQueue() {
this(false);
}
- ThreadPoolExecutor標準構(gòu)造器創(chuàng)建一個核心線程數(shù)為0、最大線程數(shù)不設限制的線程池
- 理論上可緩存線程池可以擁有無數(shù)個工作線程,即線程數(shù)量幾乎無限制。
- 可緩存線程池的workQueue為SynchronousQueue同步隊列,這個隊列類似于一個接力棒,入隊出隊必須同時傳遞,正因為可緩存線程池可以無限制地創(chuàng)建線程,不會有任務等待,所以才使用SynchronousQueue。
- 但是,maximumPoolSize的值為Integer.MAX_VALUE(非常大),可以認為可以無限創(chuàng)建線程,如果任務提交較多,就會造成大量的線程被啟動,很有可能造成OOM異常,甚至導致CPU線程資源耗盡。
1.4 newScheduledThreadPool 潛在問題
基本使用
// 線程池
ScheduledExecutorService service = Executors.newScheduledThreadPool(2);
// 批量添加線程
for (int i = 0; i < 7; i++) {
ScheduledFuture<?> future = service.scheduleWithFixedDelay(new TargetTask(), 0, 500, TimeUnit.MILLISECONDS);
}
Thread.sleep(1000);
// 線程池銷毀
service.shutdown();;
源碼分析
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
static class DelayedWorkQueue extends AbstractQueue<Runnable>
implements BlockingQueue<Runnable> {
private static final int INITIAL_CAPACITY = 16;
private RunnableScheduledFuture<?>[] queue =
new RunnableScheduledFuture<?>[INITIAL_CAPACITY];
private final ReentrantLock lock = new ReentrantLock();
private int size = 0;
private Thread leader = null;
private final Condition available = lock.newCondition();
}
maximumPoolSize為Integer.MAX_VALUE,表示線程數(shù)不設上限,其workQueue為一個DelayedWorkQueue實例,這是一個按到期時間升序排序的阻塞隊列。
1.5 總結(jié)

雖然Executors工廠類提供了構(gòu)造線程池的便捷方法,但是對于服務器程序而言,大家應該杜絕使用這些便捷方法,而是直接使用線程池ThreadPoolExecutor的構(gòu)造器,從而有效避免由于使用無界隊列可能導致的內(nèi)存資源耗盡,或者由于對線程
以上就是工作中禁止使用Executors快捷創(chuàng)建線程池原理詳解的詳細內(nèi)容,更多關(guān)于禁止用Executors創(chuàng)建線程池的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java 中使用數(shù)組存儲和操作數(shù)據(jù)
本文將介紹Java中常用的數(shù)組操作方法,通過詳細的示例和解釋,幫助讀者全面理解和掌握這些方法,具有一定的參考價值,感興趣的可以了解一下2023-09-09
Java中的關(guān)鍵字synchronized 詳解
這篇文章主要介紹了Java中的關(guān)鍵字synchronized,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-03-03
spring boot下 500 404 錯誤頁面處理的方法
本篇文章主要介紹了spring boot下 500 404 錯誤頁面處理的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-04-04
Java11中基于嵌套關(guān)系的訪問控制優(yōu)化詳解
Java(和其他語言)通過內(nèi)部類支持嵌套類,要使其正常工作,需要編譯器執(zhí)行一些技巧,下面這篇文章主要給大家介紹了關(guān)于Java11中基于嵌套關(guān)系的訪問控制優(yōu)化的相關(guān)資料,需要的朋友可以參考下2022-01-01
PostMan傳@RequestParam修飾的數(shù)組方式
這篇文章主要介紹了PostMan傳@RequestParam修飾的數(shù)組方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-08-08

