申明线程池的创建方式
Executors预置参数新建线程池
使用不当,可能导致潜在风险。
// 缓存线程池,用加速短任务执行。由于最大线程数是整数上限,使用不当可能出现并发度太高导致的效率下降问题。
Executors.newCachedThreadPool();
// 固定线程数线程池,限制并发度。固定线程数不灵活,且阻塞队列大小上限也是整数上限,使用不当可能出现内存OOM问题。
Executors.newFixedThreadPool(5);
// 单线程池,用于顺序执行任务。同上,阻塞队列上限为整数上限,使用不当可能出现内存OOM问题。
Executors.newSingleThreadExecutor();
// 周期调度线程池。由于最大线程数最整数上限,使用不当可能出现并发度太高导致效率下降问题。
Executors.newScheduledThreadPool(1);
ThreadPoolExecutor自定义(推荐)
参数上限制并发数,及队列的容量,以便于线程池更加可控
// 自己定义各参数,一般基于上诉四种预置参数线程池,做一些参数优化。
// 不建议用Executors中预定义的线程池,由于存在一些资源无限制问题。所以建议基于以上缺点自已定义合适的线程池
// 如做了并发控制的缓存线程池
new ThreadPoolExecutor(0, 100,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());
线程池的工作流程
创建线程池并提交任务
// 创建线程池
ExecutorService executor = Executors.newSingleThreadExecutor();
// 执行任务,其中xxxx为任务对象
executor.execute(xxxx);
线程池运行,执行任务
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();
}
// 如果不能添加新线程,则将任务加入队列中。如果线程池中线程为0,则新增一个(空任务)线程处理。(由于任务已经加入队列了,所以这里不再直接提交任务了)
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);
}
addworker方法解析
private boolean addWorker(Runnable firstTask, boolean core) {
// break跳转控制标记
retry:
// 循环的检查线程池状态,并更新状态(在达到合适条件后将工作线程数加1)
for (int c = ctl.get();;) {
// Check if queue empty only if necessary.
if (runStateAtLeast(c, SHUTDOWN)
&& (runStateAtLeast(c, STOP)
|| firstTask != null
|| workQueue.isEmpty()))
return false;
for (;;) {
// 再次检查工作线程数情况
if (workerCountOf(c)
>= ((core ? corePoolSize : maximumPoolSize) & COUNT_MASK))
return false;
if (compareAndIncrementWorkerCount(c))
// 退出检查循环
break retry;
c = ctl.get(); // Re-read ctl
// 检查线程池状态,至少要在RUNING或者SHUTDOWN状态才行继续处理已接收到的任务。
if (runStateAtLeast(c, SHUTDOWN))
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
}
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
// 检查完毕准备开始运行新线程
try {
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
final ReentrantLock mainLock = this.mainLock;
// 同步检查线程情况
mainLock.lock();
try {
// Recheck while holding lock.
// Back out on ThreadFactory failure or if
// shut down before lock acquired.
int c = ctl.get();
// 检查线程池运行状态,如果线程池在SHUTDOWN,则增加执行最后的任务。
// RUNNING < SHUTDOWN < STOP < TIDYING < TERMINATED
if (isRunning(c) ||
(runStateLessThan(c, STOP) && firstTask == null)) {
if (t.getState() != Thread.State.NEW)
throw new IllegalThreadStateException();
workers.add(w);
workerAdded = true;
int s = workers.size();
if (s > largestPoolSize)
largestPoolSize = s;
}
} finally {
mainLock.unlock();
}
if (workerAdded) {
// 运行新增加的线程
t.start();
workerStarted = true;
}
}
} finally {
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
运行worker
private final class Worker extends AbstractQueuedSynchronizer implements Runnable
{
// run方法,线程start调用后的运行方法
public void run() {runWorker(this);}
// 其它方法实现略
}
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
// getTask循环从任务队列中拿到任务进行处理
while (task != null || (task = getTask()) != null) {
// 获取到任务进行处理,互斥锁
w.lock();
// 检查线程池状态,及线程池中断标记情况。当前线程如果收到中断信号则进行中断
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
try {
beforeExecute(wt, task);
try {
// 运行任务
task.run();
afterExecute(task, null);
} catch (Throwable ex) {
afterExecute(task, ex);
throw ex;
}
} finally {
task = null;
w.completedTasks++;
// 释放锁
w.unlock();
}
}
completedAbruptly = false;
} finally {
processWorkerExit(w, completedAbruptly);
}
}
一个线程池中,每个线程都有一个无限循环的runWorker运行,以消费队列中的任务。线程池的核心线程是一直运行着的,在实际使用中需要评估好核心线程数,避免消耗过多资源。(默认是阻塞等待,也可设置从队列中取任务时超时时间,keepAliveTime、allowCoreThreadTimeOut。)
线程池状态说明
线程池状态值的大小比较 RUNNING < SHUTDOWN < STOP < TIDYING < TERMINATED
public static final int SIZE = 32;
private static final int COUNT_BITS = Integer.SIZE - 3;
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;
- RUNNING状态: 线程池可接收任务,可处理已接收任务。(新建线程池后,就处于当前状态)
- SHUTDOWN状态:线程池不可接收任务,可处理已接收任务。(调用shutdown方法)
- STOP状态:线程池不可接收任务,不再处理已接收任务,并会中断正在处理的任务。(调用shutdownNow方法)
- TIDYING状态:线程池不可接收任务,不再处理任务,且所有任务已终止,并执行terminated方法。(SHUTDOWN--任务队列为空、执行中任务为空->TIDYING,STOP--执行中任务为空->TIDYING)
- TERMINATED状态:线程池彻底终止,当terminated方法执行完毕后,TIDYING->TERMINATED