JUC之线程池的实现原理以及拒绝策略
线程池实现原理
向线程池提交任务后,线程池如何来处理这个任务,之前我们了解了7个参数,我们通过这些参数来串联其线程池的实现原理。
1、在创建了线程池后,开始等待请求
2、当调用execute()方法添加请求任务时:
- 如果正在运行的线程小于corePoolSize(核心线程数),那么马上创建线程执行任务;
- 如果正在运行的线程数量大于或等于corePoolSize,那么将这个任务放入阻塞队列中;
- 如果这个时候队列满了且正在运行的线程数量还小于maximumPoolSize(最大线程数),那么再创建非核心线程来执行任务
- 如果这个时候队列满了且正在运行的线程数量还大于或等于maximumPoolSize(最大线程数),那么线程池会启动饱和拒绝策略来执行
3、当一个线程完成任务时,他会从队列中取出下一个任务来执行
4、当一个线程无事可做并超过了一定的时间(KeepAliveTime)时,线程会回收。
拒绝策略
等待队列已经排满,再也塞不下新任务,同时线程池中的max线程也到达上限了,无法继续执行新任务服务,这时候就需要据拒绝策略。
内置的拒绝策略有四种:
- AbortPolicy(默认的拒绝策略):直接抛出RejectedExecutionException异常
- CallerRunPolicy:回退任务,该策略不抛弃任务,也不抛出异常,而是将任务会退给调用者,从而降低新任务的流量
- DiscardOldestPolicy:抛弃队列中等待最久的任务,然后把当前任务加人队列中尝试再次提交当前任务。
- DiscardPolicy:该策略默默地丢弃无法处理的任务,不予任何处理也不抛出异常。如果允许任务丢失,这是最好的一种策略。
根据阿里巴巴手册,定义线程池需要使用ThreadPoolExecutor来创建:
package com.JucPool;
import java.util.concurrent.*;
public class demo1 {
public static void main(String[] args) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(
2,
//根据自己的处理器数量+1
Runtime.getRuntime().availableProcessors()+1,
2L,
TimeUnit.SECONDS,
new LinkedBlockingDeque<>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
try{
for (int i = 0; i < 8; i++) {
executor.execute(()->{
System.out.println(Thread.currentThread().getName()+"\t任务执行");
});
}
} finally {
executor.shutdown();
}
}
}
如果项目时CPU密集型,则设置的线程池的最大线程数是:CPU数+1~2个。