現象
程序運行過程中無緣無故卡住,方法執行過程中停滯不前
解決
-
根據前段請求找出哪個方法卡住了,發現了方法m
-
本地debug發現每次進到m方法里面就卡住
-
不給CompletableFuture傳入ExecutorService參數(默認是ForkJoinPool)就不會卡死,一度嚴重懷疑是我們ExecutorService配置出了問題
-
m方法里面大量使用了
CompletableFuture
以及注入的線程池 -
懷疑是線程耗盡,但是我們的隊列配置得比較大,卡住的時候觀察了隊列,還剩下很多位置,原則上會執行很慢,但是不會卡住
-
於是將線程池數量從16改為200,果然成功執行,那么說明確實是線程耗盡
-
配置spring線程池:
spring.task.execution.pool.allow-core-thread-timeout=true
,意思是:core線程在閑時也會銷毀 -
發現本地即使沒有請求,線程也一直不銷毀,基本上就是死鎖了
-
分析業務代碼,類似如下(類似下面代碼):
@Test void test() throws Exception { // 使用此就會卡住 ExecutorService pool = Executors.newFixedThreadPool(1); // 使用此就不會 ExecutorService pool = ForkJoinPool.commonPool(); CompletableFuture<String> resp = CompletableFuture.supplyAsync(() -> { CompletableFuture<String> result = CompletableFuture.supplyAsync(() -> { try { SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } return "dd"; }, pool); try { result.get(); } catch (Exception e) { e.printStackTrace(); } return "ok"; }, pool); resp.get(); }
-
外層全部占用線程池的線程,而里面有需要等待內層的CompletableFuture返回結果,而內層又需要等待外層釋放線程
結果
- 死鎖造成的,ExecutorService配置的足夠大就不會出錯,但是這不治根
- 為什么forkjoinpool就不會出錯呢?forkjoinpool會源源不斷的創建線程
解決方案
不要嵌套使用CompletableFuture