目录
1、问题
某个项目,需要异步跑任务。用户创建了5个任务,然后服务器出现假死,看服务器日志,发现线程爆发式增加导致服务假死。
2、问题排查
发现跑任务的代码,用了newFixedThreadPool,而且没有释放
代码结构大致如下:
public void test() throws InterruptedException { for (int p = 0; p < 12; p++) { ExecutorService executorService = Executors.newFixedThreadPool(90); //做一些逻辑 CompletableFuture.runAsync(() -> { //todo 做一些逻辑 ExecutorService executorService2 = Executors.newFixedThreadPool(50); //做一些逻辑 CompletableFuture.runAsync(()-> { //todo 做一些逻辑2 },executorService2); }, executorService); } }
排查的时候就觉得newFixedThreadPool不会主动释放线程,线程会无限膨胀。
写个例子验证问题
2.1用newFixedThreadPool
public static void main(String[] args) throws InterruptedException { testFixThread(); //打断点 System.out.println("开始查看总线程--"); Thread.sleep(5000); }
public static void testFixThread(){ for(int p=0;p<3;p++){ ExecutorService executorService = Executors.newFixedThreadPool(5); // 执行结果 List<CompletableFuture<Void>> resultList = Lists.newArrayList(); for (int i = 0; i < 10; i++) { int finalI = i; CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(()->{ System.out.println("线程1:,"+Thread.currentThread().getName()+","+finalI); },executorService); resultList.add(completableFuture); } resultList.forEach(CompletableFuture::join); // executorService.shutdown(); List<CompletableFuture<Void>> resultList1 = Lists.newArrayList(); ExecutorService executorService2 = Executors.newFixedThreadPool(6); for (int i = 0; i < 7; i++) { int finalI = i; CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(()->{ System.out.println("线程2:,"+Thread.currentThread().getName()+","+finalI); },executorService2); resultList1.add(completableFuture); } resultList1.forEach(CompletableFuture::join); // executorService2.shutdown(); } }
、
(1)不主动释放线程池,执行到开始查看总线程,发现还有33个线程没有释放 (2)主动释放线程池,线程正常释放
2.2用ThreadPoolExecutor
public static void main(String[] args) throws InterruptedException { testTheadExcetor(); System.out.println("开始查看总线程--"); Thread.sleep(5000); }
public static void testTheadExcetor(){ for(int p=0;p<3;p++){ ExecutorService executorService = new ThreadPoolExecutor(2, 5, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(100), new ThreadPoolExecutor.CallerRunsPolicy()); // 执行结果 List<CompletableFuture<Void>> resultList = Lists.newArrayList(); for (int i = 0; i < 10; i++) { int finalI = i; CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(()->{ System.out.println("线程1:,"+Thread.currentThread().getName()+","+finalI); },executorService); resultList.add(completableFuture); } resultList.forEach(CompletableFuture::join); // executorService.shutdown(); List<CompletableFuture<Void>> resultList1 = Lists.newArrayList(); ExecutorService executorService2 = new ThreadPoolExecutor(2, 6, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(100), new ThreadPoolExecutor.CallerRunsPolicy()); for (int i = 0; i < 7; i++) { int finalI = i; CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(()->{ System.out.println("线程2:,"+Thread.currentThread().getName()+","+finalI); },executorService2); resultList1.add(completableFuture); } resultList1.forEach(CompletableFuture::join); // executorService2.shutdown(); } }
发现有15个核心线程没有释放
3、总结
(1)newFixedThreadPool不会主动释放线程,ThreadPoolExecutor会保留核心线程
(2)用newFixedThreadPool要主动释放线程,免得引起线程膨胀