【Java】线程池的实现原理是怎样的?CPU密集型任务与IO密集型任务的区别?
一、CPU密集型与IO密集型任务
1.CPU密集型任务(CPU-bound)
定义:需要大量CPU计算资源,大部分时间都在进行运算的任务。
这类任务的特点是计算量大,CPU占用率高。
特点:
- 主要消耗CPU资源
- 执行速度取决于CPU的计算能力
- 通常涉及复杂的数学运算、算法处理等。
常见例子:
- 视频编码/解码
- 3D图形渲染
- 复杂的数学计算(如密码学运算、科学计算)
- 机器学习模型训练
优化策略:
- 使用更高效的算法
- 增加CPU的核心数(多进程/多线程)
- 使用向量化指令(如SIMD)
- 减少不必要的计算
2.IO密集型任务(I/O bound)
定义:需要大量输入/输出操作,大部分时间在等待IO操作完成的任务。这类任务的特点是CPU利用率不高,大部分时间在等待。
特点:
- 主要消耗IO资源(磁盘、网络)
- 执行速度取决于IO设备的速度
- CPU经常处于等待状态
常见例子:
- 文件读写操作
- 数据库查询
- 网络请求(如 HTTP API调用)
- 消息队列处理
- 日志记录
优化策略:
- 使用异步IO
- 增加并发处理能力
- 使用缓存减少IO操作
- 优化IO设备性能(如SSD代替HDD)
二、线程池实现原理
1.线程池核心组件
Java中的线程池主要通过ThreadPoolExecutor类实现,其核心组件包括:
1.工作队列(BlockingQueue):用于存放待执行的任务
2.线程集合(HashSet<Worker>
):实际执行任务的线程
3.线程工厂(ThreadFactory):用于创建新线程
4.拒绝策略(RejectedExecutionHandler): 当任务无法处理时的策略。
2.线程池工作流程
1.提交任务到线程池
2.如果当前线程数<corePoolSize,创建新线程执行任务
3.如果线程数>=corePoolSize,将任务放入工作队列
4.如果队列已满且线程数<maximumPoolSize,创建新线程执行任务,
5.如果队列已满且线程数>=maximumPoolSize,执行拒绝策略。
3.线程池状态管理
线程池通过AtomicInteger变量同时维护两个信息:
- 运行状态(RUNNING, SHUTDOWN, STOP, TIDYING, TERMINATED)
- 有效线程数(workerCount)
4.关键参数(3大核心配置)
- corePoolSize:核心线程数,线程池维护的最小活跃线程数。
- maximumPoolSize:最大线程数,线程池可创建的线程上限。
- keepAliveTime: 非核心线程的空闲存活时间,超时则销毁(核心线程默认不销毁)。