知识卡片

默认公共池不放阻塞任务

普通读书笔记卡 · 1543

内容

不指定执行器时,runAsync()/supplyAsync() 默认用公共 ForkJoinPool,线程数等于 CPU 核数,全应用共享——一旦某类任务混入慢 IO,线程会长期占池不释放,造成线程饥饿,拖累其他本该很快的 CPU 任务。正确做法是按 [[按任务类型配线程]] 建独立线程池,显式传参,不共用默认公共池。

参考来源

- 位置:《Java高并发核心编程.卷2,多线程、锁、JMM、JUC、高并发设计模式》第10章《CompletableFuture异步回调》10.1.6节《线程池的使用》(源文件:_epub-src/OEBPS/Text/chapter305.xhtml) - 结论依据:原文说明“默认情况下,通过静态方法runAsync()、supplyAsync()创建的CompletableFuture任务会使用公共的ForkJoinPool线程池,默认的线程数是CPU的核数”,并明确警告“如果所有CompletableFuture共享一个线程池,那么一旦有任务执行一些很慢的IO操作,就会导致线程池中的所有线程都阻塞在IO操作上,造成线程饥饿,进而影响整个系统的性能。所以,强烈建议大家根据不同的业务类型创建不同的线程池”,因此推出本卡结论。 - 原始内容:默认情况下,通过静态方法runAsync()、supplyAsync()创建的CompletableFuture任务会使用公共的ForkJoinPool线程池,默认的线程数是CPU的核数……如果所有CompletableFuture共享一个线程池,那么一旦有任务执行一些很慢的IO操作,就会导致线程池中的所有线程都阻塞在IO操作上,造成线程饥饿,进而影响整个系统的性能。所以,强烈建议大家根据不同的业务类型创建不同的线程池,以避免互相干扰。