线程池作用
- 利用线程池管理并复用线程、控制最大并发数等
- 实现任务线程队列缓存策略和拒绝机制
- 实现某些与时间相关的功能,如定时执行、周期执行等
- 隔离线程环境,比如,交易服务和搜索服务在同一台服务器上,分别开启两个线程池,交易线程的资源消耗明显要大;因此,通过配置独立的线程池,将较慢的交易服务与搜索服务隔离开,避免各服务线程相互影响.
线程池好处
- 降低资源消耗: 通过重复利用已创建的线程,降低创建和销毁线程造成的系统资源消耗
- 提高响应速度: 当任务到达时,任务可以不需要等到线程创建就能立即执行
- 提高线程的可管理性: 线程是稀缺资源,如果过多地创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一分配、调优和监控。
线程池构造解析
1 | public ThreadPoolExecutor(int corePoolSize, |
七个参数解析:
1. corePoolSize
线程池中的常驻核心线程数,一般不会被回收。
如果 executor.allowCoreThreadTimeOut(true) ,那么核心线程如果不干活(闲置状态)的话,超过一定时间( keepAliveTime),就会被销毁掉
2. maximumPoolSize
线程池能容纳同时执行的最大线程数,线程总数计算公式 = 核心线程数 + 非核心线程数。
3. keepAliveTime
非核心空闲线程的存活时间。
4. TimeUnit
keepAliveTime 的时间单位。
5. workQueue
任务队列,存放被提交但尚未执行的任务。
6. threadFactory
生成线程池中工作线程的线程工厂。
7. handler
拒绝策略。
- hreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
- ThreadPoolExecutor.DiscardPolicy:丢弃任务,但是不抛出异常。
- ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列等待最久的任务,然后重新尝试执行任务(重复此过程)
- ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务
JDK 自带的线程池
1 | // 单线程 |
一般不会直接使用以上三种,而是手写 ThreadPoolExecutor 实现线程池,因为阻塞队列的最大值为 Integer.MAX_VALUE ,会造成OOM。
合理配置线程池
1. cpu 密集型:(需要大量运算,不会阻塞,宜少配置线程数)
cpu核心数+1
2. IO 密集型:(需要大量IO,会阻塞,宜多配置线程数)
cpu核心数*2