三十五、线程池之ThreadPoolExecutor

142 阅读20分钟

线程池之ThreadPoolExecutor

ThreadPoolExecutor的七个核心参数

public ThreadPoolExecutor(
	int corePoolSize,                    // 最大核心工作线程数
	int maximumPoolSize,                 // 最大工作线程数
	long keepAliveTime,                  // 普通工作线程存活时间
	TimeUnit unit,                       // 时间单位
	BlockingQueue<Runnable> workQueue,   // 任务队列
	ThreadFactory threadFactory          // 线程工厂
	RejectedExecutionHandler handler     // 任务拒绝策略
	) {
	if (corePoolSize < 0 ||
		maximumPoolSize <= 0 ||
		maximumPoolSize < corePoolSize ||
		keepAliveTime < 0)
		throw new IllegalArgumentException();
	if (workQueue == null || threadFactory == null || handler == null)
		throw new NullPointerException();
	this.acc = System.getSecurityManager() == null ?
			null :
			AccessController.getContext();
	this.corePoolSize = corePoolSize;
	this.maximumPoolSize = maximumPoolSize;
	this.workQueue = workQueue;
	this.keepAliveTime = unit.toNanos(keepAliveTime);
	this.threadFactory = threadFactory;
	this.handler = handler;
}
  • 核心工作线程在任务执行结束后是不会被销毁的,调用的是take方法从任务队列中获取数据
  • 普通工作线程在任务执行结束后,调用poll方法从任务队列中获取数据,等待的时间就是keepAliveTime参数的值。过了等待时间没有拿到任务,线程就会销毁
  • 当没有核心工作线程执行任务时,任务会被放到任务队列中
  • 线程工厂用于创建线程,可以设置线程的一些属性信息
  • 任务拒绝策略是在线程池中没有空闲线程执行任务时触发,对新来的任务进行处理

JDK提供的四种任务拒绝策略:

  • AbortPolicy:当前拒绝策略会在线程池无法处理任务时,直接抛出异常
  • CallerRunsPolicy:当前拒绝策略会在线程池无法处理任务时,将任务交给调用者处理
  • DiscardPolicy:当前拒绝策略会在线程池无法处理任务时,直接将任务丢弃掉
  • DiscardOldestPolicy:当前拒绝策略会在线程池无法处理任务时,将队列中最早的任务丢弃掉,并且将当前任务再交给线程池处理

ThreadPoolExecutor的简单使用

public static void main(String[] args) throws ExecutionException, InterruptedException {
	// 1.构建线程池
	ThreadPoolExecutor pool = new ThreadPoolExecutor(
			2,
			5,
			10,
			TimeUnit.SECONDS,
			new ArrayBlockingQueue<>(10),
			new ThreadFactory() {
				@Override
				public Thread newThread(Runnable r) {
					Thread thread = new Thread(r);
					thread.setName("test-ThreadPoolExecutor");
					return thread;
				}
			},
			new MyRejectedExecution()
	);

	pool.execute(() -> {
		System.out.println("没有返回结果的任务");
	});

	Future<Object> future = pool.submit(() -> {
		System.out.println("有返回结果的任务");
		return "返回结果";
	});

	Object s = future.get();
	System.out.println(s);

	pool.shutdown();
}

// 自定义任务拒绝策略
private static class MyRejectedExecution implements RejectedExecutionHandler {
	@Override
	public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
	}
}

ThreadPoolExecutor的源码

ThreadPoolExecutor的核心属性


// ctl的高3位代表线程池的状态,低29位代表线程池中的线程数,所以线程池的线程数不可能达到整数最大值
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
// COUNT_BITS的值是29,定义出来方便后面的运算
private static final int COUNT_BITS = Integer.SIZE - 3;
// CAPACITY的值:00011111 11111111 11111111 11111111,线程池最大线程数
private static final int CAPACITY   = (1 << COUNT_BITS) - 1;

// 下面都是线程池的状态
// RUNNING(111):线程池只有处于此状态,才能够正常接收任务和执行任务
private static final int RUNNING    = -1 << COUNT_BITS;
// SHUTDOWN(000):此状态的线程池不再接收新任务,但是会执行完正在执行的任务和队列中的任务
private static final int SHUTDOWN   =  0 << COUNT_BITS;
// STOP(001):此状态的线程池不再接收新任务,只会执行完正在执行的任务,不会执行队列中的任务
private static final int STOP       =  1 << COUNT_BITS;
// TIDYING(010):此状态是从SHUTDOWN或者STOP状态变化而来,线程池马上要关闭,是一个过渡状态
private static final int TIDYING    =  2 << COUNT_BITS;
// TERMINATED(011):此状态是从TIDYING转变而来,执行了terminated方法,代表线程池已关闭
private static final int TERMINATED =  3 << COUNT_BITS;

// runStateOf方法是获取线程池状态
private static int runStateOf(int c)     { return c & ~CAPACITY; }
// workerCountOf方法是获取线程池的线程数
private static int workerCountOf(int c)  { return c & CAPACITY; }

image.png

ThreadPoolExecutor的构造方法

public ThreadPoolExecutor(int corePoolSize,
				int maximumPoolSize,
				long keepAliveTime,
				TimeUnit unit,
				BlockingQueue<Runnable> workQueue,
				ThreadFactory threadFactory,
				RejectedExecutionHandler handler) {
	// 健壮性参数校验
	if (
		// 核心工作线程数不能小于0
		corePoolSize < 0 ||
		// 最大工作线程数不能小于等于0
		maximumPoolSize <= 0 ||
		// 最大工作线程数不能小于核心线程数
		maximumPoolSize < corePoolSize ||
		// 普通工作线程空闲时间不能小于0
		keepAliveTime < 0)
		throw new IllegalArgumentException();
	// 任务队列,线程工厂,拒绝策略都不能为空
	if (workQueue == null || threadFactory == null || handler == null)
		throw new NullPointerException();
	// 系统资源相关,与线程池业务无关,不用关心
	this.acc = System.getSecurityManager() == null ?
			null :
			AccessController.getContext();
	this.corePoolSize = corePoolSize;
	this.maximumPoolSize = maximumPoolSize;
	this.workQueue = workQueue;
	this.keepAliveTime = unit.toNanos(keepAliveTime);
	this.threadFactory = threadFactory;
	this.handler = handler;
}

ThreadPoolExecutor的execute方法

  1. 如果任务为空,直接抛出异常
  2. 获取ctl核心属性
  3. 如果工作线程数小于最大核心工作线程数,创建核心工作线程执行任务
  4. 如果创建核心工作线程执行任务失败,说明可能是线程池状态变化了,或者线程数达到最大核心线程数
  5. 如果是线程池状态变化了,执行拒绝策略
  6. 如果是线程数变化了,将任务放到任务队列中,如果放入失败了说明队列满了
  7. 于是创建普通线程执行任务,如果失败则执行拒绝策略
  8. 如果任务成功放入队列中,再次判断线程池状态是否是RUNNING
  9. 如果不是,从队列中移除任务,并且执行拒绝策略
  10. 如果是,判断线程池中是否有工作线程,如果没有则创建普通工作线程
public void execute(Runnable command) {
	if (command == null)
		// 任务为null,直接抛空指针异常
		throw new NullPointerException();
	// 获取ctl核心属性
	int c = ctl.get();
	// 判断工作线程数是否小于核心工作线程数
	if (workerCountOf(c) < corePoolSize) {
		// 工作线程数小于核心工作线程数
		// 创建核心工作线程执行任务是否成功
		if (addWorker(command, true))
			// 创建工作线程执行任务成功,直接返回
			return;
		// 创建工作线程执行任务失败
		// 失败的原因可能是线程数量等于核心工作线程数,也可能是线程池状态发生变化
		// 再次获取ctl核心属性
		c = ctl.get();
	}
	// 判断线程池是否处于RUNNING状态
	// 如果处于RUNNING状态,任务放入任务队列是否成功
	if (isRunning(c) && workQueue.offer(command)) {
		// 任务放入队列成功,再次获取ctl核心属性
		int recheck = ctl.get();
		// 可能任务放到队列中,线程池状态就变化了
		// 所以这里判断线程池是否还是RUNNING状态
		// 如果不是,从队列中删除任务是否成功
		if (! isRunning(recheck) && remove(command))
			// 从队列中删除任务成功,执行拒绝策略
			reject(command);
		// 判断线程池的工作线程数是否为0
		// 走到这里,说明工作线程数已经大于等于核心工作线程数了
	    // 如果workerCountOf(recheck) == 0说明最大核心工作线程数设置为0
		else if (workerCountOf(recheck) == 0)
			// 线程池的工作线程数为0
			// 创建普通工作线程
			addWorker(null, false);
	}
	// 判断创建普通工作线程执行任务是否成功
	else if (!addWorker(command, false))
		// 创建普通工作线程执行任务失败,执行拒绝策略
		reject(command);
}

addWorker方法:

  1. 进入外层for死循环
  2. 获取ctl属性值以及线程池状态
  3. 如果线程池状态大于等于SHUTDOWN,并且线程池状态不为SHUTDOWN,直接返回false
  4. 如果线程池状态为SHUTDOWN,但是有新任务进来,或者任务队列为空,直接返回false
  5. 如果线程池状态为RUNNING,或者为SHUTDOWN,但是没有新任务进来并且任务队列不为空,则继续往下执行
  6. 进入内层for死循环
  7. 获取工作线程数
  8. 判断工作线程数是否已经达到最大值,如果已达到,返回false
  9. 如果未达到,通过CAS将ctl+1
  10. 如果CAS操作失败,判断线程池状态是否变化,如果变化,执行外层for循环;如果没有,执行内层for循环
  11. CAS操作成功,将任务封装成Worker对象,此时新的工作线程已经通过线程工厂创建出来了
  12. 如果新的工作线程为null,说明线程工厂有问题,返回false
  13. 如果新的工作线程不为null,加锁
  14. 如果当前线程池状态不是RUNNING或者SHUTDOWN,返回false;如果是SHUTDOWN,但是有新任务,也返回false
  15. 判断新的工作线程是否已经启动,如果是,抛出异常
  16. 如果未启动,将Worker对象放到HashSet中
  17. 获取当前线程池中线程个数,如果线程个数大于largestPoolSize属性值,这赋值给largestPoolSize
  18. 释放锁,启动新的工作线程,返回true
private boolean addWorker(Runnable firstTask, boolean core) {
	retry:
	for (;;) {
		// ----------------判断线程池状态-------------------------
		// 获取ctl核心属性
		int c = ctl.get();
		// 获取线程池状态
		int rs = runStateOf(c);

		// 判断线程池状态是否>=SHUTDOWN,如果是,则说明线程池状态不为RUNNING
		// 如果线程池状态为SHUTDOWN,并且任务已经放到队列中,队列不会空
		// 说明需要创建工作线程去执行任务
		// 但是上面的三个条件有一个不满足的话,就不需要创建线程去执行任务,直接返回false
		if (rs >= SHUTDOWN &&
			! (rs == SHUTDOWN &&
			   firstTask == null &&
			   ! workQueue.isEmpty()))
			return false;

		for (;;) {
		// ---------------判断线程个数------------------------
			// 获取工作线程个数
			int wc = workerCountOf(c);
			// 判断线程个数是否满足要求
			if (wc >= CAPACITY ||
				wc >= (core ? corePoolSize : maximumPoolSize))
				// 线程个数已经达到最大,返回false
				return false;
			// 通过CAS对ctl值+1
			if (compareAndIncrementWorkerCount(c))
				// ctl+1操作成功,跳出外层for循环
				break retry;
			// ctl+1失败,再次获取ctl值
			c = ctl.get();  
			// 判断当前线程池状态与之前读取的状态是否一致
			if (runStateOf(c) != rs)
				// 状态不一致
				// 继续外循环
				continue retry;
		}
	}

	// ------------------创建工作线程,并且启动------------------
	// 线程是否已经启动的标识变量
	boolean workerStarted = false;
	// 线程是否已经放到HashSet中的标识变量
	boolean workerAdded = false;
	Worker w = null;
	try {
		// 使用ThreadFactory创建线程,并且封装成Worker对象
		w = new Worker(firstTask);
		// 获取线程对象
		final Thread t = w.thread;
		// 判断线程是否为null
		if (t != null) {
			// 线程不为null
			final ReentrantLock mainLock = this.mainLock;
			mainLock.lock();
			try {
				// 获取线程池状态
				int rs = runStateOf(ctl.get());
				// 判断线程池状态是否为RUNNING
				// 如果不是,判断线程池状态是否为SHUTDOWN,并且任务已经放到队列中
				if (rs < SHUTDOWN ||
					(rs == SHUTDOWN && firstTask == null)) {
					// 判断线程是否已经执行start方法
					if (t.isAlive()) 
						// ThreadFactory创建线程时,也执行了start方法,这是不允许的
						// 所以直接抛出异常
						throw new IllegalThreadStateException();
					// 将worker对象放到HashSet中
					workers.add(w);
					// 获取当前线程池的线程个数
					int s = workers.size();
					// 判断线程个数是否大于largestPoolSize
					if (s > largestPoolSize)
						// 更新largestPoolSize值
						largestPoolSize = s;
					// 添加线程成功
					workerAdded = true;
				}
			} finally {
				mainLock.unlock();
			}
			// 判断是否添加线程成功
			if (workerAdded) {
				// 添加线程成功,启动线程
				t.start();
				// 启动线程成功
				workerStarted = true;
			}
		}
	} finally {
		// 判断线程是否启动成功
		if (! workerStarted)
			// 线程启动失败
			// addWorkerFailed方法的作用
			// ctl的值-1
			// 将线程从HashSet中删除
			addWorkerFailed(w);
	}
	return workerStarted;
}

addWorkerFailed方法:

  1. 加锁
  2. 如果Worker不为null,将其从HashSet中移除
  3. 将ctl-1
  4. 因为只有线程工厂创建线程时将线程启动了,addWorker方法抛出异常了,才会执行addWorkerFailed方法
  5. 所以此线程池被当做异常的线程池,所以尝试将线程池状态转变为TIDYING或者TERMINATED
  6. 释放锁
private void addWorkerFailed(Worker w) {
	final ReentrantLock mainLock = this.mainLock;
	mainLock.lock();
	try {
		// 判断worker对象是否为null
		if (w != null)
			// worker对象不为null
			// 从HashSet中删除worker对象
			workers.remove(w);
		// ctl值-1
		decrementWorkerCount();
		// 尝试将线程池状态转变为TIDYING或者TERMINATED
		tryTerminate();
	} finally {
		mainLock.unlock();
	}
}

Worker内部类

继承了AQS,重写了AQS中多个方法

private final class Worker extends AbstractQueuedSynchronizer implements Runnable
{
	private static final long serialVersionUID = 6138294804551838833L;
	// Worker中的线程
	final Thread thread;
	// 线程的任务
	Runnable firstTask;
	// 统计线程执行了多少个任务
	volatile long completedTasks;

	Worker(Runnable firstTask) {
		// Worker刚创建时,state值设置为-1
		setState(-1);
		this.firstTask = firstTask;
		// Worker是通过线程工厂创建线程的
		// 而且将自己作为任务传给线程,线程会执行Worker的run方法
		this.thread = getThreadFactory().newThread(this);
	}

	public void run() {
		// 线程任务
		runWorker(this);
	}

	// 中断线程要执行的方法
	void interruptIfStarted() {
		Thread t;
		// 只有在state值>=0,并且线程没有被中断时,才允许中断
		if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
			try {
				t.interrupt();
			} catch (SecurityException ignore) {
			}
		}
	}

	// -----------------下面的方法被重写了,不太重要----------------------
	protected boolean isHeldExclusively() {
		return getState() != 0;
	}

	protected boolean tryAcquire(int unused) {
		if (compareAndSetState(0, 1)) {
			setExclusiveOwnerThread(Thread.currentThread());
			return true;
		}
		return false;
	}

	protected boolean tryRelease(int unused) {
		setExclusiveOwnerThread(null);
		setState(0);
		return true;
	}

	public void lock()        { acquire(1); }
	public boolean tryLock()  { return tryAcquire(1); }
	public void unlock()      { release(1); }
	public boolean isLocked() { return isHeldExclusively(); }

}

runWorker方法:

  1. 获取新创建的工作线程
  2. 将Worker对象中的state设置成0
  3. 如果Worker对象中的任务不为null,或者从队列中获取任务不为null,进入while循环
  4. 加锁
  5. 如果线程池状态大于等于STOP,并且线程没有被中断,线程中断
  6. 执行beforeExecute方法
  7. 执行任务
  8. 执行afterExecute方法
  9. Worker对象中的completedTasks值+1,代表完成的任务数量
  10. 释放锁,进入下一个循环
  11. 如果Worker对象中的任务为null,并且从队列中获取任务也为null,将completedAbruptly设置成false,执行processWorkerExit方法
final void runWorker(Worker w) {
	// 获取当前线程,即新创建的工作线程
	Thread wt = Thread.currentThread();
	// 获取当前任务
	Runnable task = w.firstTask;
	w.firstTask = null;
	// Worker重写了很多AQS方法,执行unlock方法,会将state值设置为0
	// 此时线程可以被中断
	w.unlock();
	// 线程是否异常结束的标志,默认是异常结束
	boolean completedAbruptly = true;
	try {
		while (task != null || (task = getTask()) != null) {
			// lock方法将state从0变成1
			// 此时线程不能被中断,也就是说SHUTDOWN方法无法中断此线程
			w.lock();

			if ((runStateAtLeast(ctl.get(), STOP) ||
				 (Thread.interrupted() &&
				  runStateAtLeast(ctl.get(), STOP))) &&
				!wt.isInterrupted())
				// 上面的判断保证进入这里说明线程池已经处于STOP以上的状态
				// 需要中断线程
				wt.interrupt();
			try {
				// beforeExecute啥也没实现
				// 程序猿可以实现,在任务执行前输出一些日志
				beforeExecute(wt, task);
				Throwable thrown = null;
				try {
					// 执行任务
					task.run();
				} catch (RuntimeException x) {
					thrown = x; throw x;
				} catch (Error x) {
					thrown = x; throw x;
				} catch (Throwable x) {
					thrown = x; throw new Error(x);
				} finally {
					// afterExecute啥也没实现
					afterExecute(task, thrown);
				}
			} finally {
				task = null;
				// 任务执行完毕,执行任务数量+1
				w.completedTasks++;
				// 此时线程可以被中断 
				w.unlock();
			}
		}
		// while循环结束,正常走到这里,getTask方法中会将ctl-1
		completedAbruptly = false;
	} finally {
		// 任务执行完,处理线程
		processWorkerExit(w, completedAbruptly);
	}
}

processWorkerExit方法:

  1. 如果completedAbruptly为true,说明线程是异常结束,ctl的值-1
  2. 加锁
  3. 将线程执行过的任务数量加到线程池统计的属性中
  4. 将Worker从HashSet中移除
  5. 释放锁
  6. 执行tryTerminate方法
  7. 如果线程池的状态小于STOP,但是线程异常结束,执行addWorker方法
  8. 如果线程正常结束,如果allowCoreThreadTimeOut值为false,那么min值为最大核心工作线程数
  9. 如果allowCoreThreadTimeOut值为false,那么min值为0
  10. 如果min值为0,并且任务队列不为空,min值赋值为1
  11. 如果线程池中线程数大于min值,直接返回,否则,执行addWorker方法,以保证队列中的任务有线程去执行
  12. 如果线程池状态大于等于STOP,直接返回
private void processWorkerExit(Worker w, boolean completedAbruptly) {
	// 判断线程是否是异常结束
	if (completedAbruptly)
		// 线程异常结束
		// ctl的值-1
		decrementWorkerCount();

	final ReentrantLock mainLock = this.mainLock;
	mainLock.lock();
	try {
		// 将线程执行的任务数加到线程池的统计属性中
		completedTaskCount += w.completedTasks;
		// 将线程从HashSet中移除
		workers.remove(w);
	} finally {
		mainLock.unlock();
	}

	tryTerminate();

	// 获取ctl的值
	int c = ctl.get();
	// 判断线程池的状态是否小于STOP
	if (runStateLessThan(c, STOP)) {
		if (!completedAbruptly) {
			// 线程池的状态小于STOP,并且线程不是异常结束
			// 如果核心工作线程允许超时,min为0,否则min为最大核心工作线程数
			int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
			if (min == 0 && ! workQueue.isEmpty())
				// 如果没有核心工作线程,并且任务队列中有任务
				// min值设置为1,代表至少要创建一个线程去执行任务
				min = 1;
			if (workerCountOf(c) >= min)
				// 线程池中的线程数大于等于1,说明有线程执行任务
				// 直接返回
				return; 
		}
		// 创建线程去执行任务
		// 如果线程池状态异常,线程不会创建成功
		addWorker(null, false);
	}
}

getTask方法:

  1. timeOut变量赋值为false
  2. 进入for死循环
  3. 获取ctl值和线程池状态
  4. 如果线程池状态大于等于SHUTDOWN并且任务队列为空,或者线程池状态大于等于STOP,ctl-1,并且返回null
  5. 如果线程池状态正常,获取工作线程数
  6. 如果核心线程允许超时或者工作线程数大于最大核心工作线程数,timed赋值true
  7. 如果核心线程不允许超时并且工作线程数小于等于最大核心工作线程数,timed赋值false
  8. 如果timed和timedOut都为true,并且工作线程数大于1或者任务队列为空,通过CAS将ctl-1,然后返回null
  9. 如果CAS失败,则执行continue
  10. 如果timed或者timedOut为false,或者工作线程数小于等于1并且任务队列不为空,判断timed值
  11. 如果timed为true,说明是普通工作线程,使用poll方法从队列中获取任务
  12. 如果timed为false,说明是核心工作线程,使用take方法从队列中获取任务
  13. 线程被唤醒后,如果拿到任务,将任务返回
  14. 如果没有拿到任务,将timedOut设置为true,继续for循环
private Runnable getTask() {

	// 第一次执行方法,timeOut值为false
	boolean timedOut = false;

	for (;;) {
		// 获取ctl的值
		int c = ctl.get();
		// 获取线程池的状态
		int rs = runStateOf(c);

		if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
			// 线程池异常,或者任务队列中没有任务
			// ctl的值-1,并且返回null
			decrementWorkerCount();
			return null;
		}

		// 获取工作线程数量
		int wc = workerCountOf(c);

		// timed为false,说明全是核心工作线程,并且核心工作线程从队列中拿任务没有时间限制
		// timed为true,说明要么核心工作线程从队列中拿任务有时间限制
		// 要么当前线程池中的线程数大于最大核心线程数,那么此时创建的线程肯定为普通工作线程
		boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

		if ((wc > maximumPoolSize || (timed && timedOut))
			&& (wc > 1 || workQueue.isEmpty())) {
			// 第一次循环,进不了这里,因为timedOut值为false,wc > maximumPoolSize也一定为false
			// 后面的循环可能进入这里,进入这里说明存在工作线程,但是没有任务
			if (compareAndDecrementWorkerCount(c))
				// ctl的值-1,并且返回null
				return null;
			// ctl的值修改失败,说明有并发的情况
			// 重新走一次for循环
			continue;
		}

		try {
			// timed为true,无论是核心工作线程,还是普通工作线程,从队列中拿任务都有时间限制
			// timed为false,说明是核心工作线程,并且从队列中拿任务没有时间限制
			Runnable r = timed ?
				workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
				workQueue.take();
			if (r != null)
				// 拿到任务,返回任务
				return r;
			// 没有拿到任务,将timedOut设置为true
			// timedOut为true,会在上面的if语句中退出getTask方法
			timedOut = true;
		} catch (InterruptedException retry) {
			timedOut = false;
		}
	}
}

shutdownNow方法

  1. 加锁
  2. 如果线程池状态小于STOP,将状态改成STOP
  3. 中断线程池中的所有线程
  4. 将任务队列清空,并且将队列中的任务赋值给tasks
  5. 释放锁
  6. 将线程池状态改成TERMINATED
  7. 返回任务队列中的任务
// shutdownNow方法不会处理阻塞队列中的任务,将任务全部返回
public List<Runnable> shutdownNow() {
	List<Runnable> tasks;
	final ReentrantLock mainLock = this.mainLock;
	mainLock.lock();
	try {
		// checkShutdownAccess方法与系统资源调度有关,与线程池业务无关
		// 不用关心
		checkShutdownAccess();
		// 线程池状态大于等于STOP不用变
		// 否则将线程池状态改成STOP
		advanceRunState(STOP);
		// 中断线程池中的线程
		interruptWorkers();
		// 将任务队列中的任务清空,并且返回
		tasks = drainQueue();
	} finally {
		mainLock.unlock();
	}
	// 将线程池的状态改变为TERMINATED
	tryTerminate();
	return tasks;
}

advanceRunState方法:

  1. 进入for死循环
  2. 获取ctl的值
  3. 如果线程池状态大于等于STOP,啥也不做
  4. 如果线程池状态小于STOP,将状态改成STOP
  5. 退出循环并且返回
// targetState值为STOP
private void advanceRunState(int targetState) {
	for (;;) {
		// 获取ctl核心属性
		int c = ctl.get();
		if (runStateAtLeast(c, targetState) ||
			ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c))))
			// 线程池的状态已经大于等于STOP
			// 或者线程池状态变成STOP,而且没有改变线程个数
			// 退出for循环
			break;
	}
}

interruptWorkers方法:

  1. 加锁
  2. 遍历HashSet中所有的线程,并且中断他们
  3. 释放锁
private void interruptWorkers() {
	final ReentrantLock mainLock = this.mainLock;
	mainLock.lock();
	try {
		for (Worker w : workers)
			w.interruptIfStarted();
	} finally {
		mainLock.unlock();
	}
}

drainQueue方法:

private List<Runnable> drainQueue() {
	BlockingQueue<Runnable> q = workQueue;
	ArrayList<Runnable> taskList = new ArrayList<Runnable>();
	// drainTo方法是阻塞队列提供的方法
	// 将本队列内容清空,并且放到另一个队列中
	q.drainTo(taskList);
	// drainTo方法有时候清不空队列,所以这里保险一些,再做个判断
	if (!q.isEmpty()) {
		for (Runnable r : q.toArray(new Runnable[0])) {
			if (q.remove(r))
				taskList.add(r);
		}
	}
	return taskList;
}

tryTerminate方法:

  1. 进入for死循环
  2. 获取ctl的值
  3. 如果线程池状态为RUNNING,或者大于等于TIDYING,或者为SHUTDOWN并且队列中有任务,直接返回
  4. 如果线程池中有工作线程,中断空闲工作,直接返回
  5. 加锁
  6. 通过CAS将线程池状态改成TIDYING
  7. 如果修改成功,调用terminated方法,然后将状态改成TERMINATED
  8. 唤醒调用awaitTermination方法阻塞的线程,释放锁,然后返回。此方法是将提交任务给线程池的线程堵塞了。
  9. 如果修改失败,释放锁,进入下一个for循环
final void tryTerminate() {
	for (;;) {
		// 获取ctl核心属性
		int c = ctl.get();
		if (isRunning(c) ||
			runStateAtLeast(c, TIDYING) ||
			(runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
			// 线程池状态为RUNNING
			// 或者线程池状态大于等于TIDYING
			// 或者线程池状态为SHUTDOWN,并且阻塞队列中有任务
			// 直接返回
			return;
		// ----------到这里说明线程池状态要么是STOP,要么是SHUTDOWN但是没有任务-------
		if (workerCountOf(c) != 0) { 
			// 线程池中存在工作线程
			// 中断工作线程
			interruptIdleWorkers(ONLY_ONE);
			return;
		}

		final ReentrantLock mainLock = this.mainLock;
		mainLock.lock();
		try {
			if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
				// 线程池状态改成TIDYING成功了
				try {
					// 此处的terminated方法是空方法
					terminated();
				} finally {
					// 线程池状态改成TERMINATED
					ctl.set(ctlOf(TERMINATED, 0));
					// 此处唤醒调用了awaitTermination方法的线程
					// awaitTermination方法的作用是让提交任务给线程池的线程阻塞,等待任务执行完毕后,再做其他操作
					termination.signalAll();
				}
				return;
			}
		} finally {
			mainLock.unlock();
		}
	}
}

shutdown方法

  1. 加锁
  2. 如果线程池状态大于等于SHUTDOWN,啥也不做
  3. 否则将线程池状态改成SHUTDOWN
  4. 将空闲线程中断
  5. 执行onShutdown方法
  6. 释放锁
  7. 尝试将线程池状态改成TERMINATED
public void shutdown() {
	final ReentrantLock mainLock = this.mainLock;
	mainLock.lock();
	try {
		checkShutdownAccess();
		// 线程池状态大于等于SHUTDOWN不用变
		// 否则将线程池状态改成SHUTDOWN
		advanceRunState(SHUTDOWN);
		// 将空闲线程中断
		interruptIdleWorkers();
		// onShutdown方法是空方法
		onShutdown();
	} finally {
		mainLock.unlock();
	}
	// 将线程池状态改成TERMINATED
	tryTerminate();
}

interruptIdleWorkers方法:

  1. 加锁
  2. 遍历HashSet中的线程
  3. 如果线程没有中断,并且线程没有执行任务,将线程中断
  4. 将Worker的state值改成0
  5. 释放锁
private void interruptIdleWorkers() {
	interruptIdleWorkers(false);
}

private void interruptIdleWorkers(boolean onlyOne) {
	final ReentrantLock mainLock = this.mainLock;
	mainLock.lock();
	try {
		for (Worker w : workers) {
			Thread t = w.thread;
			// tryLock方法是通过CAS将state值从0变成1
			// 由于正在执行任务的线程已经将state值变成1了,所以再执行tryLock必定返回false
			// 所以以下条件只有空闲线程才能满足
			if (!t.isInterrupted() && w.tryLock()) {
				try {
					t.interrupt();
				} catch (SecurityException ignore) {
				} finally {
					w.unlock();
				}
			}
			// 入参传的就是false
			if (onlyOne)
				break;
		}
	} finally {
		mainLock.unlock();
	}
}

线程池核心参数设置

任务的类型有可能是CPU密集型、IO密集型,也有可能是混合型。由于任务类型不可控,所以线程池的核心参数设置比较困难

最好的方法是结合当前的业务,在测试环境下进行压力测试,通过监控线程池状态,以及动态修改线程池的核心参数,得到最佳的线程池参数

ThreadPoolExecutor提供了线程池核心属性的get和set方法,可以通过这些方法实现对线程池的动态监测和修改

网上也提供了很多开源框架,例如hippo4j(中国人写的),与springboot整合了,可以直接拿来使用