线程池实现原理
线程池的原理是:调用方的线程向线程池的队列中提交任务,线程池的线程从队列中取任务进行处理。
实现一个线程池需要考虑的问题
1、队列设置多长?如果是无界队列可能会因为队列过长导致内存耗尽,如果是有界队列,队列满了该怎么处理。
2、线程池中的线程数是固定的还是动态变化的?
3、提交任务时,是放入队列还是创建新线程。
4、没有任务时线程是进入睡眠还是阻塞,如果阻塞该怎么唤醒?问题4通常有3种做法:
(1)不使用阻塞队列,使用线程安全的队列,没有阻塞–唤醒机制。当队列为空时,线程睡眠一段时间后醒来查看有没有新任务,不断轮询。
(2)不使用阻塞队列,但在线程池内部实现阻塞–唤醒机制。
(3)使用阻塞队列。
做法(3)最好,即不用轮询消耗系统资源,也不用去实现轮询–唤醒机制,所以ThreadPoolExecutor和ScheduledThreadPoolThread采用了阻塞队列。
线程池的类继承体系
ThreadPoolExecutor
ThreadPoolExecutor的结构
public class ThreadPoolExecutor extends AbstractExecutorService {
...
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); //状态变量
private final BlockingQueue<Runnable> workQueue; // 任务阻塞队列
private final ReentrantLock mainLock = new ReentrantLock(); // 互斥锁
private final HashSet<Worker> workers = new HashSet<Worker>(); // 线程集合
}
private final class Worker
extends AbstractQueuedSynchronizer
implements Runnable
{
final Thread thread; // Work的线程
Runnable firstTask; // 第一个任务
volatile long completedTasks; // 执行完的任务数
}
核心参数
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;
}
(1)corePoolSize:线程池中保持的线程数
(2)maxPoolSize:在corePoolSize和队列都满了的情况下,线程数能扩充的最大值
(3)keepAliveTime/TmieUnit:maxPoolSize多余的线程的存活时间和时间单位
(4)blockingQueue:线程池所用的队列
(5)threadFactory:线程创建工厂
(6)RejectedExecutionHandler:maxPoolSize满了时的拒绝策略。
线程池的生命周期与关闭
线程池的状态变量ctl分为两部分:高三位用来表示线程池的状态,后29位表示线程数量。
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private static final int COUNT_BITS = Integer.SIZE - 3;
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
private static final int RUNNING = -1 << COUNT_BITS;
private static final int SHUTDOWN = 0 << COUNT_BITS;
private static final int STOP = 1 << COUNT_BITS;
private static final int TIDYING = 2 << COUNT_BITS;
private static final int TERMINATED = 3 << COUNT_BITS;
private static int runStateOf(int c) { return c & ~CAPACITY; }// 获取运行状态
private static int workerCountOf(int c) { return c & CAPACITY; } // 获取线程数量
private static int ctlOf(int rs, int wc) { return rs | wc; } // 获取ctl,rs是runState,ws是workState
线程池的状态有五个,只能从小的向大的转移。
有两个方法可以关闭线程,shutdown()和shutdownNow()。
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess(); // 检测是否有关闭线程池的权限
advanceRunState(SHUTDOWN); // 设置线程池状态
interruptIdleWorkers(); // 中断空闲线程
onShutdown(); // 空的钩子函数
} finally {
mainLock.unlock();
}
tryTerminate();
}
public List<Runnable> shutdownNow() {
List<Runnable> tasks;
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();
advanceRunState(STOP);
interruptWorkers(); // 中断所有的线程
tasks = drainQueue(); // 清空队列
} finally {
mainLock.unlock();
}
tryTerminate();
return tasks;
}
两个方法里中断的线程类型不同
private void interruptIdleWorkers(boolean onlyOne) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker w : workers) {
Thread t = w.thread;
if (!t.isInterrupted() && w.tryLock()) { // tryLock()成功说明该线程空闲,才中断该线程
try {
t.interrupt();
} catch (SecurityException ignore) {
} finally {
w.unlock();
}
}
if (onlyOne)
break;
}
} finally {
mainLock.unlock();
}
}
private void interruptWorkers() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker w : workers)
w.interruptIfStarted(); //直接中断线程
} finally {
mainLock.unlock();
}
}
shutdown()和shutdownNow()都调用了tryTerminate()。
final void tryTerminate() {
for (;;) {
int c = ctl.get();
if (isRunning(c) ||
runStateAtLeast(c, TIDYING) ||
(runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
return;
if (workerCountOf(c) != 0) { // Eligible to terminate
interruptIdleWorkers(ONLY_ONE);
return;
}
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) { // 切换线程状态
try {
terminated(); // 调用空实现的钩子函数
} finally {
ctl.set(ctlOf(TERMINATED, 0)); // 修改线程状态
termination.signalAll(); // 唤醒因为termination阻塞的线程
}
return;
}
} finally {
mainLock.unlock();
}
// else retry on failed CAS
}
}
线程池关闭的步骤
awaitTermination的实现:
public boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException {
long nanos = unit.toNanos(timeout);
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (;;) {
if (runStateAtLeast(ctl.get(), TERMINATED)) // 判断是否是TERMINATED状态,如果是直接返回
return true;
if (nanos <= 0)
return false;
nanos = termination.awaitNanos(nanos); // 如果不是TERMINATED状态,则睡眠指定的时间后再次判断
}
} finally {
mainLock.unlock();
}
}
这里的睡眠与前面的tryTerminate()里的termination.signalAll()相对应。
参考资料:《Java并发实现原理:JDK源码剖析》