线程池的作用
- 池化技术,规避频繁创建线程和销毁线程带来的一些额外性能损耗。
- 使用线程池可以更好的去控制线程的数量,从而更好的去发挥CPU的性能。
- 在做SpringBoot项目时,想做异步处理或者是一些定时任务时,会采用@Async,@Scheduled。这些注解的底层都会让你的异步任务或者定时任务基于他提供的线程池中的线程去处理。
- 比如Web容器,Tomcat内部就有线程池,所有请求到Web服务后,第一步就是交给Tomcat线程池中的线程去做的处理。
- 在一些批处理或者数据体量相对比较大的时候,可以上线程池在做并行处理,从单线程串行处理,优化为多线程并行处理,性能必然会有一些提升。依然需要使用线程池来实现。
ThreadPoolExecutor线程池参数
public ThreadPoolExecutor(int corePoolSize, // 核心线程数
int maximumPoolSize, // 最大线程数
long keepAliveTime, // 最大空闲时间
TimeUnit unit, // 最大空闲时间单位
BlockingQueue<Runnable> workQueue, // 阻塞队列
ThreadFactory threadFactory, // 线程工程
RejectedExecutionHandler handler) { // 拒绝策略
线程池执行任务流程
// 核心属性, 高3位:维护线程池的状态,低29位维护工作线程的个数
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
// 核心线程数没满,就创建核心线程执行任务
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
// 核心线程满了,先判断线程池装是否为running,如果是running就进行排队
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
// 队列满了,创建非核心线程处理
else if (!addWorker(command, false))
// 创建非核心线程失败,执行拒绝策略。
reject(command);
}
线程池的核心属性
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
int类型占用4个字节,每个字节占用8个bit位。int就有32个bit位。
高三个bit位,维护线程池状态。
低29个bit位,维护工作线程个数。
线程池的状态
// 正常接收线程,排队的线程也正常执行,正在执行的线程也正常执行
private static final int RUNNING = -1 << COUNT_BITS;
// 拒绝接收新线程,排队的线程正常执行,正在执行的线程也正常执行
private static final int SHUTDOWN = 0 << COUNT_BITS;
// 拒绝接收新检查,排队的线程丢弃掉,正常执行的线程强制中断
private static final int STOP = 1 << COUNT_BITS;
// 由SHUTDOWN和STOP状态自动转换过来
private static final int TIDYING = 2 << COUNT_BITS;
// 由TIDYING状态转换过来,转换之前会执行terminated()方法(这个方法给用户重载使用,执行自定义逻辑)
private static final int TERMINATED = 3 << COUNT_BITS;
状态流程图