java 線程池默認(rèn)提供了幾種拒絕策略
java 線程池默認(rèn)提供了幾種拒絕策略:

這幾個策略都實現(xiàn)了RejectedExecutionHandler,拿DiscardOldestPolicy來說,查看源碼:

核心代碼只有2行:
e.getQueue().poll() 從列表里彈出1個(最早的)任務(wù),以便讓隊列空出1個位置
e.execute(r) 新任務(wù)放入隊列執(zhí)行
從這段代碼來看,如果有任務(wù)被丟棄(即:從隊列里彈出了),不會有任何報錯,也沒有日志可查,實際使用中不太方便監(jiān)控這種情況。
?
我們可以參考這段源碼,自定義策略:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import
?java.util.concurrent.RejectedExecutionHandler;
import
?java.util.concurrent.ThreadPoolExecutor;
?
public
?class
?CustomDiscardPolicy?
implements
?RejectedExecutionHandler {
?
????
//額外傳入1個名稱,方便打日志或埋點監(jiān)控時,定位問題
????
private
?String factoryName =?
""
;
?
????
public
?CustomDiscardPolicy(String factoryName) {
????????
this
.factoryName = factoryName;
????
}
?
????
public
?void
?rejectedExecution(Runnable r, ThreadPoolExecutor e) {
????????
if
?(!e.isShutdown()) {
????????????
Runnable poll = e.getQueue().poll();
????????????
//這里可以加一些自己的處理(比如:埋點監(jiān)控)
????????????
System.err.println(
"["
?+?
this
.factoryName +?
"]task will be discard:"
?+ poll);
????????????
e.execute(r);
????????
}
????
}
}
當(dāng)然,這里出于演示目的,只打了一行錯誤信息,實際應(yīng)用中大家可以埋點發(fā)到kafka之類(以便后續(xù)做實時監(jiān)控預(yù)警)。
測試一下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Test
public
?void
?testThreadPool()?
throws
?InterruptedException {
????
final
?ThreadFactory DEMO_THREAD_FACTORY =?
new
?ThreadFactoryBuilder().setNameFormat(
"demo-POOL-%d"
).build();
?
????
final
?ExecutorService DEMO_POOL =?
new
?ThreadPoolExecutor(
1
,?
2
, 300L, TimeUnit.MILLISECONDS,
????????????
new
?LinkedBlockingQueue<>(
5
), DEMO_THREAD_FACTORY,?
new
?CustomDiscardPolicy(
"demo-POOL"
));
?
????
for
?(
int
?i =?
0
; i <?
10
; i++) {
????????
DEMO_POOL.submit(() -> {
????????????
try
?{
????????????????
System.out.println(Thread.currentThread().getId() +?
" ready!"
);
????????????????
//假設(shè)線程干活,需要一段時間
????????????????
Thread.sleep(
500
);
????????????????
System.out.println(
"\t"
?+ Thread.currentThread().getId() +?
" done!"
);
????????????
}?
catch
?(Exception e) {
????????????
}
????????
});
????
}
????
//等一會兒,讓線程池都跑完,再結(jié)束main
????
Thread.sleep(
10000
);
}
提交了10個任務(wù),線程池必然飽和(10>2+5),會丟棄一些早期任務(wù),輸出如下:

從輸出看,丟了3個任務(wù),符合預(yù)期。
標(biāo)簽: