執行緒池在開發中一定會用到,如果能像golang一樣,java語言也有協程,也許java程式員就少了一種包袱,
回歸正題,我們聊下到底有哪些執行緒池的使用方式,總結有以下幾種,
- JDK 內置執行緒池
- Spring執行緒池
- 自己魔改封裝
1、JDK 內置執行緒池
常用的有:

我們看下最全的執行緒池引數,探究為什么阿里規約不建議使用Executors創建默認個數的執行緒池,
/**
引數【7個】
corePoolSize - 即使空閑時仍保留在池中的執行緒數,除非設定 allowCoreThreadTimeOut
maximumPoolSize - 池中允許的最大執行緒數
keepAliveTime - 當執行緒數大于內核時,這是多余的空閑執行緒在終止前等待新任務的最大時間,
unit - keepAliveTime引數的時間單位
workQueue - 用于在執行任務之前使用的佇列, 這個佇列將僅保存execute方法提交的Runnable任務,
threadFactory - 執行程式創建新執行緒時使用的工廠
handler - 執行被阻止時使用的處理程式,因為達到執行緒限制和佇列容量
四個預定義的處理程式策略
在默認ThreadPoolExecutor.AbortPolicy ,處理程式會引發運行RejectedExecutionException后排斥反應,
在ThreadPoolExecutor.CallerRunsPolicy中,呼叫execute本身的執行緒運行任務, 這提供了一個簡單的反饋控制機制,將降低新任務提交的速度,
在ThreadPoolExecutor.DiscardPolicy中 ,簡單地洗掉無法執行的任務,
在ThreadPoolExecutor.DiscardOldestPolicy中 ,如果執行程式沒有關閉,則作業佇列頭部的任務被洗掉,然后重試執行(可能會再次失敗,導致重復),
**/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.acc = System.getSecurityManager() == null ?
null :
AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
1.1 阿里規約原文
執行緒池不允許使用Executors去創建,而是通過ThreadPoolExecutor的方式,這樣的處理方式讓寫的同學更加明確執行緒池的運行規則,規避資源耗盡的風險,
說明:Executors回傳的執行緒池物件的弊端如下:
-
1)FixedThreadPool和SingleThreadPool:
允許的請求佇列長度為Integer.MAX_VALUE,可能會堆積大量的請求,從而導致OOM,
-
2)CachedThreadPool:
允許的創建執行緒數量為Integer.MAX_VALUE,可能會創建大量的執行緒,從而導致OOM,
1.2 阿里規約是否是多余的?不然jdk為啥提供這個api?
答案可以看下ThreadPoolExecutor類的上的注釋,已翻譯成中文:
為了在廣泛的背景關系中有用,此類提供了許多可調引數和可擴展性鉤子, 然而,程式員被敦促使用更方便的Executors工廠方法Executors.newCachedThreadPool() (無限執行緒池,具有自動執行緒回收), Executors.newFixedThreadPool(int) (固定大小的執行緒池)和Executors.newSingleThreadExecutor() (單個后臺執行緒),可以預先配置最常用的使用場景設定, 否則,手動配置和調優此類時,請使用以下指南...
其實這個類的作者"Doug Lea",已經說明Executors.newCachedThreadPool(),Executors.newFixedThreadPool(int),應該是在什么情況下使用?
只是一般程式員是不會去仔細看類說明檔案,都是跟著百度復制過來的代碼就干起活來了,
說起來也慚愧之前在2010年培訓的時候,其實是會看這個jdk api檔案的,但那個時候似乎很懵,也不會去詳盡的看檔案背后的一些知識點,
所以說看第一手材料多么重要,作者已經把該注意的點都寫到類說明檔案注釋里了,嚇得我趕緊用到一個類都去細看下檔案注釋,解決不了再找度娘,
1.3 執行緒池不為人知的幾個冷門知識點
從幾個面試題來一一道來,
1.核心和最大執行緒池是否都可以動態修改?
可以使用setCorePoolSize(int)和setMaximumPoolSize(int)進行動態 更改
2.核心執行緒最初創建并且只有在新任務到達時才啟動?
可以使用方法prestartCoreThread()或prestartAllCoreThreads()動態地覆寫,如果您使用非空佇列構建池,則可能需要預先提供執行緒,
3.核心執行緒是否一定不終止?
不一定,報錯或者allowCoreThreadTimeOut(boolean)也可以用于將這個超時策略應用于核心執行緒,只要keepAliveTime值不為零
4.如何給執行緒池添加一個啟動/暫停的功能?
class PausableThreadPoolExecutor extends ThreadPoolExecutor {
private boolean isPaused;
private ReentrantLock pauseLock = new ReentrantLock();
private Condition unpaused = pauseLock.newCondition();
public PausableThreadPoolExecutor(...) { super(...); }
protected void beforeExecute(Thread t, Runnable r) {
super.beforeExecute(t, r);
pauseLock.lock();
try {
while (isPaused) unpaused.await();
} catch (InterruptedException ie) {
t.interrupt();
} finally {
pauseLock.unlock();
}
}
public void pause() {
pauseLock.lock();
try {
isPaused = true;
} finally {
pauseLock.unlock();
}
}
public void resume() {
pauseLock.lock();
try {
isPaused = false;
unpaused.signalAll();
} finally {
pauseLock.unlock();
}
}
}}
2、Spring執行緒池
官方已經實作的全部7個TaskExecuter,Spring宣稱對于任何場景,這些TaskExecuter完全夠用了:
| 名字 | 特點 |
|---|---|
| SimpleAsyncTaskExecutor | 每次請求新開執行緒,沒有最大執行緒數設定.不是真的執行緒池,這個類不重用執行緒,每次呼叫都會創建一個新的執行緒,限流是通過 ConcurrencyThrottleSupport類的monitor的wait(),notify() 實作的 |
| SyncTaskExecutor | 不是異步的執行緒.同步可以用SyncTaskExecutor,但這個可以說不算一個執行緒池,因為還在原執行緒執行,這個類沒有實作異步呼叫,只是一個同步操作, |
| ConcurrentTaskExecutor | Executor的適配類,不推薦使用,如果ThreadPoolTaskExecutor不滿足要求時,才用考慮使用這個類, |
| SimpleThreadPoolTaskExecutor | 監聽Spring’s lifecycle callbacks,并且可以和Quartz的Component兼容.是Quartz的SimpleThreadPool的類,執行緒池同時被quartz和非quartz使用,才需要使用此類, |
| ThreadPoolTaskExecutor | 最常用,要求jdk版本大于等于5,可以在程式而不是xml里修改執行緒池的配置.其實質是對java.util.concurrent.ThreadPoolExecutor的包裝, |
| TimerTaskExecutor | |
| WorkManagerTaskExecutor |
- 使用ThreadPoolExecutorFactoryBean
package org.springframework.scheduling.concurrent;
public class ThreadPoolExecutorFactoryBean extends ExecutorConfigurationSupport implements FactoryBean<ExecutorService>, InitializingBean, DisposableBean {
private int corePoolSize = 1;
private int maxPoolSize = 2147483647;
private int keepAliveSeconds = 60;
private boolean allowCoreThreadTimeOut = false;
private int queueCapacity = 2147483647;
private boolean exposeUnconfigurableExecutor = false;
@Nullable
private ExecutorService exposedExecutor;
public ThreadPoolExecutorFactoryBean() {
}
...
protected ThreadPoolExecutor createExecutor(int corePoolSize, int maxPoolSize, int keepAliveSeconds, BlockingQueue<Runnable> queue, ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {
return new ThreadPoolExecutor(corePoolSize, maxPoolSize, (long)keepAliveSeconds, TimeUnit.SECONDS, queue, threadFactory, rejectedExecutionHandler);
}
- 使用ScheduledExecutorFactoryBean
package org.springframework.scheduling.concurrent;
public class ScheduledExecutorFactoryBean extends ExecutorConfigurationSupport implements FactoryBean<ScheduledExecutorService> {
private int poolSize = 1;
@Nullable
private ScheduledExecutorTask[] scheduledExecutorTasks;
private boolean removeOnCancelPolicy = false;
private boolean continueScheduledExecutionAfterException = false;
private boolean exposeUnconfigurableExecutor = false;
@Nullable
private ScheduledExecutorService exposedExecutor;
public ScheduledExecutorFactoryBean() {
}
-
使用ThreadPoolTaskExecutor
這個類可以設定回呼方法 -
使用ThreadPoolTaskScheduler
這個類可以設定回呼方法,包裝錯誤處理類,錯誤不會影響執行下一個任務@Scheduled就是使用這個類包裝的,注意核心默認一個執行緒,會阻塞任務
@Override
public void run() {
try {
this.delegate.run();
}
catch (UndeclaredThrowableException ex) {
this.errorHandler.handleError(ex.getUndeclaredThrowable());
}
catch (Throwable ex) {
this.errorHandler.handleError(ex);
}
}
參考
[java8 api] https://www.matools.com/api/java8
[spring執行緒池(同步、異步)] https://www.cnblogs.com/duanxz/p/9435343.html
掃描二維碼,關注公眾號“猿必過”

回復 “面試題” 自行領取吧,
微信群交流討論,請添加微信號:zyhui98,備注:面試題加群
本文由猿必過 YBG 發布
禁止未經授權轉載,違者依法追究相關法律責任
如需授權可聯系:[email protected]
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/266203.html
標籤:Java
上一篇:dubbo實戰之一:準備和初體驗
下一篇:springmvc回傳json
