ForkJoinPool与普通线程池的区别
请说明ForkJoinPool与ThreadPoolExecutor的核心区别,以及为什么ForkJoinPool更适合分治任务。
回答
Yahuda
| 特性 | ThreadPoolExecutor | ForkJoinPool |
|---|---|---|
| 任务类型 | 独立任务 | 分治任务(可分解为子任务) |
| 队列结构 | 共享阻塞队列 | 每个线程一个双端队列(Deque) |
| 负载均衡 | 无,队列FIFO | 工作窃取(Work-Stealing) |
| 任务调度 | 外部提交或内部执行 | fork/join框架,父子任务协作 |
| 线程数 | 固定+弹性 | 默认CPU核数-1(commonPool) |
| 阻塞等待 | 线程池无关 | join()时其他线程窃取其队列任务 |
| 适用场景 | IO密集型/通用任务 | CPU密集计算/递归分治任务 |
ForkJoinPool特殊机制:
- 任务队列双端:线程从队头取任务执行;窃取线程从队尾偷任务。
- join()优化:线程调用join()等待子任务时,不会阻塞等待,而是执行其他任务(包括窃取的任务)。
- ManagedBlocker:处理外部阻塞(如I/O)时动态增加线程。
选择建议:
- 普通异步任务(Runnable/Callable)→ ThreadPoolExecutor。
- 递归分治(数组排序、矩阵乘法)→ ForkJoinPool。
- 并行流(parallelStream)默认使用ForkJoinPool.commonPool()。