前言
线程池最大的作用就是复用线程。在线程池中,经过同一个线程去执行不一样的任务,减少反复地创建线程带来的系统开销,就是线程的复用。那么线程池线程复用的原理是什么呢?
之前面试被问到线程池复用的原理时,由于对源码不甚了解,回答的不好。因此这篇文章将深入源码,理解线程复用到底时如何实现的。
一、线程池核心属性
首先我们看看线程池的核心属性,这也是面试中经常被问到的问题。
public class ThreadPoolExecutor extends AbstractExecutorService {
//线程状态,高3为表示线程池状态,低29位表示线程数量
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
//Lock锁
private final ReentrantLock mainLock = new ReentrantLock();
//条件变量
private final Condition termination = mainLock.newCondition();
//线程集合
private final HashSet<Worker> workers = new HashSet<>();
//核心线程数
private volatile int corePoolSize;
//最大线程数
private volatile int maximumPoolSize;
//阻塞队列
private final BlockingQueue<Runnable> workQueue;
//非核心线程存活时间
private volatile long keepAliveTime;
//线程工厂,所有线程使用线程工厂创建
private volatile ThreadFactory threadFactory;
//拒绝策略,是一个函数式接口
private volatile RejectedExecutionHandler handler;
}
二、execute源码
我们可以从execute() 方法开始,查看线程复用的原理
private static final int COUNT_BITS = Integer.SIZE - 3; //32-3
private static final int COUNT_MASK = (1 << COUNT_BITS) - 1; 2^29-1
//c & COUNT_MASK; 返回低29位,也就是线程树
private static int workerCountOf(int c) { return c & COUNT_MASK; }
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
/*
* Proceed in 3 steps:
*
* 1. If fewer than corePoolSize threads are running, try to
* start a new