本来想把实现类统一写一篇的,但是发现每个实现类其实都够让我喝一壶的,集中在一起有恐无法详尽其精髓,遂单独起了一篇来详细展开下ThreadPoolExecutor与AQS黑魔方的关系和一些细节。
ThreadPoolExecutor是JDK提供的线程池基础类,里面定义了线程池的一些核心属性(比如核心线程数、最大线程数、keepAlive时间、拒绝策略等),其内部包含了线程池下对线程的基本操作封装,方便开发者在其基础上快速地使用线程池技术。
ThreadPoolExecutor的核心处理逻辑无外乎围绕线程池启停与运行时线程操作相关进行的,所以下面将从这几个动作为出发点,先以图形的形式描绘处理流程,再结合代码深入剖析其内部实现,由面到点地去深入一窥线程池的内部运行原理。
在源码中可以看到到处都有使用到ctl这个变量,其核心围绕的是它的两个状态表示,线程池状态和worker数量。
开发性(beforeExecute、afterExecute)
/*
* RUNNING: Accept new tasks and process queued tasks
* SHUTDOWN: Don't accept new tasks, but process queued tasks
* STOP: Don't accept new tasks, don't process queued tasks,
* and interrupt in-progress tasks
* TIDYING: All tasks have terminated, workerCount is zero,
* the thread transitioning to state TIDYING
* will run the terminated() hook method
* TERMINATED: terminated() has completed
/线程池启动方法具体流程(启动线程,sumbit核心是execute,所以先看一下execute,方法处理流程如下)
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();
}
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);
}拒绝请求:依赖拒绝策略处理器RejectedExecutionHandler来处理线程
final void reject(Runnable command) {
handler.rejectedExecution(command, this);
}核心线程会因为从阻塞队列中获取不到资源而保持阻塞状态
错了,如果拿不到资源超时就会退出了,如果大于coreSize会释放掉线程。
如何做到线程池的优雅停机的?
线程池的监控要怎么做?- to看源码
通过before和after可以做一些动作。
没细看到这个,有一个decrement逻辑,可能是这个地方
那必须是比我写的好,抽象的逻辑概念也挺好的,不过还是挺难看懂的,涉及到的双属性整型ctl、AQS、mainLock操作都是很硬核的概念,尤其是worker里面的哪个thread包装,如果看漏了容易把人整懵,容易以为直接把原生的Runnable丢给了底层调用,最后发现线程运行的还是执行器worker。
【学习价值】ThreadPoolExecutor内部使用了很多锁,其原理也可作为并发编程的学习范本,非常具备学习价值。
【原理的作用】Threadlocal中涉及的概念比较多,了解其worker、队列进出逻辑对性能优化和问题排查都十分必要。