线程池底层原理《二》
一、线程池ThreadPoolExecutor底层如何实现复用
- 当线程数小于核心线程数时,创建线程
- 当线程数大于等于核心线程数,且任务队列未满时,将任务放入任务队列
- 当线程数大于等于核心线程数,且任务队列已满时,
(1) 若线程数小于最大线程数,创建线程
(2) 若线程数等于最大线程数,抛出异常,拒绝任务
二、线程队列满了任务会丢失么
- 如果队列满了,且任务总数大于最大线程数走当前线程走拒绝策略。
- 可以自定义拒绝异常,将该任务缓存到Redis、本地文件、MySQL中后期项目启动实现补偿。
- AbortPolicy 丢弃任务,抛运行时异常。
- CallerRunsPolicy 执行任务。
- DiscardPolicy 忽视,什么都不会发生。
- DiscardOldestPolicy 从队列中剔除最先进入队列(最后一个执行)的任务。
- 实现RejectedExecutionHandler接口,可自定义处理器。
三、线程池拒绝策略有哪些
- AbortPolicy 丢弃任务,抛运行时异常。
- CallerRunsPolicy 执行任务。
- DiscardPolicy 忽视,什么都不会发生。
- DiscardOldestPolicy 从队列中剔除最先进入队列(最后一个执行)的任务。
- 实现RejectedExecutionHandler接口,可自定义处理器。
四、为什么阿里巴巴不建议使用Executors
因为默认的Executors线程池底层是基于ThreadPoolExecutor构造函数封装的,采用无界队列存放缓存任务,会一直缓存任务,容易发生线程池队列溢出。
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
五、实际项目中哪些地方使用了线程池
- 实际开发项目中,禁止自己new线程。
- 必须使用线程池来维护和创建线程。