线程池,工程设计中到处可见,但是我们有没有细看过其原理,有没有联系到设计时的相关问题。这些将是本篇讨论的核心。
文章结构:
1)什么是线程池?为什么使用线程池以及优点是什么?
2)Java常见线程池
3)Java线程池的架构设计与demo
4)Java线程池状态
5)线程池处理任务的过程
6)源码阅读分析
7)思考几个问题
一、什么是线程池?为什么使用线程池以及优点是什么?
(1)线程池概念:
对于线程池,其实就是存放一定数量线程的一个线程集合。
线程池允许若个线程同时允许,允许同时运行的线程数量就是线程池的容量;当添加的到线程池中的线程超过它的容量时,会有一部分线程阻塞等待。线程池会通过相应的调度策略和拒绝策略,对添加到线程池中的线程进行管理。
(2)为什么需要线程池
假设一个服务器完成一项任务所需时间为:T1 创建线程时间,T2 在线程中执行任务的时间,T3 销毁线程时间。如果:T1 + T3 远大于 T2,则可以采用线程池,以提高服务器性能。线程池技术正是关注如何缩短或调整T1,T3时间的技术。
(3)线程池优点
1、线程是稀缺资源,使用线程池可以减少创建和销毁线程的次数,每个工作线程都可以重复使用。
2、可以根据系统的承受能力,调整线程池中工作线程的数量,防止因为消耗过多内存导致服务器崩溃。
二、Java常见线程池
(1)newSingleThreadExecutor
单个线程的线程池,即线程池中每次只有一个线程工作,单线程串行执行任务。
保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。如果这个线程异常结束,会有另一个取代它,保证顺序执行。单工作线程最大的特点是可保证顺序地执行各个任务,并且在任意给定的时间不会有多个线程是活动的。
(2)newFixedThreadExecutor(n)
固定数量的线程池,每提交一个任务就是一个线程,直到达到线程池的最大数量,然后后面进入等待队列直到前面的任务完成才继续执行。
但是,在线程池空闲时,即线程池中没有可运行任务时,它不会释放工作线程,还会占用一定的系统资源。
(3)newCacheThreadExecutor(推荐使用)
可缓存线程池,当线程池大小超过了处理任务所需的线程,那么就会回收部分空闲(一般是60秒无执行)的线程,当有任务来时,又智能的添加新线程来执行。
(4)newScheduleThreadExecutor
大小无限制的线程池,支持定时和周期性的执行线程
三、Java线程池的架构设计与demo
首先,我们要清楚线程池与普通的Thread、Runnable定义的线程的区别。线程池已经把线程、任务、执行的概念进行了设计拆分。我们下面从它的架构设计上看出个一二来。
(1)Excuctor
它是"执行者"接口,它是来执行任务的。Executor提供了execute()接口来执行已提交的 Runnable 任务的对象。Executor存在的目的是提供一种将"任务提交"与"任务如何运行"分离开来的机制。
(2)ExecutorService
ExecutorService继承于Executor。它是"执行者服务"接口,它是为"执行者接口Executor"服务而存在的;准确的话,ExecutorService提供了"将任务提交给执行者的接口(submit方法)","让执行者执行任务(invokeAll, invokeAny方法)"的接口等等。
(3)AbstractExecutorService
AbstractExecutorService是一个抽象类,它实现了ExecutorService接口。
AbstractExecutorService存在的目的是为ExecutorService中的函数接口提供了默认实现
(4)ThreadPoolExecutor
ThreadPoolExecutor就是Java出了名的线程池。
(5)ScheduledExecutorService
它继承于于ExecutorService。它相当于提供了"延时"和"周期执行"功能的ExecutorService。
ScheduledExecutorService提供了相应的函数接口,可以安排任务在给定的延迟后执行,也可以让任务周期的执行。
(6)ScheduledThreadPoolExecutor
继承于ThreadPoolExecutor,并且实现了ScheduledExecutorService接口。它相当于提供了"延时"和"周期执行"功能的ScheduledExecutorService。
ScheduledThreadPoolExecutor类似于Timer,但是在高并发程序中,ScheduledThreadPoolExecutor的性能要优于Timer。
(7)Executors
Executors是个静态工厂类。它通过静态工厂方法返回ExecutorService、ScheduledExecutorService、ThreadFactory 和 Callable 等类的对象。
四、Java线程池状态
(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;
<1>Running:可以接受新任务,同时也可以处理阻塞队列里面的任务;
<2>Shutdown:不可以接受新任务,但是可以处理阻塞队列里面的任务;
<3>Stop:不可以接受新任务,也不处理阻塞队列里面的任务,同时还中断正在处理的任务;
<4>Tidying:属于过渡阶段,在这个阶段表示所有的任务已经执行结束了,当前线程池中是不存在有效的线程的,并且将要调用terminated方法;
<5>Terminated:终止状态,这个状态是在调用完terminated方法之后所处的状态;
状态转换:
在调用shutdown方法的时候,线程池状态会从Running转换成Shutdown;
在调用shutdownNow方法的时候,线程池状态会从Running/Shutdown转换成Stop;
当线程池在SHUTDOWN状态下,并在阻塞队列为空同时线程池为空的情况下,线程池状态会从Shutdown转换成Tidying;
当线程池在STOP状态下,并在线程池为空的情况下,线程池状态会从Stop转换成Tidying;
当线程池处在TIDYING状态时,并调用terminated方法之后,线程池状态会从Tidying转换成Terminate;
(2)从线程池运行的线程角度分析线程池状态:
(1):poolSize < corePoolSize,则直接创建新的线程(核心线程)来执行当前提交的任务;
(2):poolSize = corePoolSize,并且此时阻塞队列没有满,那么会将当前任务添加到阻塞队列中,如果此时存在工作线程(非核心线程)的话,那么会由工作线程来处理该阻塞队列中的任务,如果此时工作线程数量为0的话,那么会创建一个工作线程(非核心线程)出来;
(3):poolSize = corePoolSize,并且此时阻塞队列已经满了,那么会直接创建新的工作线程(非核心线程)来处理阻塞队列中的任务;
(4):poolSize = maximumPoolSize,并且此时阻塞队列也满了的话,那么会触发拒绝机制,具体决绝策略采用的是什么就要看我们创建ThreadPoolExecutor的时候传入的RejectExecutionHandler参数了;
五、线程池处理任务的过程:
图取自《Java并发编程的艺术》
提交一个任务到线程池中,线程池的处理流程如下:
1、判断线程池里的核心线程是否都在执行任务,如果不是(核心线程空闲或者还有核心线程没有被创建)则创建一个新的工作线程来执行任务。如果核心线程都在执行任务,则进入下个流程。
2、线程池判断工作队列是否已满,如果工作队列没有满,则将新提交的任务存储在这个工作队列里。如果工作队列满了,则进入下个流程。
3、判断线程池里的线程是否都处于工作状态,如果没有,则创建一个新的工作线程来执行任务。如果已经满了,则交给饱和策略来处理这个任务。
也就是:如果运行的线程少于 corePoolSize,则 Executor始终首选添加新的线程,而不进行排队。(如果当前运行的线程小于corePoolSize,则任务根本不会存放,添加到queue中,而是直接抄家伙(thread)开始运行)
如果运行的线程等于或多于 corePoolSize,则 Executor始终首选将请求加入队列,而不添加新的线程。
六、源码阅读分析:
从原始接口Excuctor开始分析,分析到我们常用线程池ThreadPoolExecutor
参考文章
(1)Excuctor
Executor提供了execute()接口来执行已提交的 Runnable 任务的对象。Executor存在的目的是提供一种将"任务提交"与"任务如何运行"分离开来的机制。
public interface Executor {
/*
包含了一个方法execute,参数为一个Runnable接口引用。
Executor接口将任务的提交与执行分离开来。
*/
void execute(Runnable command);
}
(2)ExecutorService
public interface ExecutorService extends Executor {
// 启动关闭流程,执行以前提交的任务,但不接受新任务。
void shutdown();
/*
在调用shutdownNow方法的时候,线程池状态会从Running/Shutdown转换成Stop;
不可以接受新任务,也不处理阻塞队列里面的任务,同时还中断正在处理的任务;
*/
List<Runnable> shutdownNow();
/**
如果此执行程序已关闭,则返回 true。
*/
boolean isShutdown();
/*
如果关闭后所有任务都已完成,则返回 true
*/
boolean isTerminated();
/**
请求关闭、发生超时或者当前线程中断,无论哪一个首先发生之后,都将导致阻塞,直到所有任务完成执行。
*/
boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException;
/**
提交一个返回值的任务用于执行,返回一个表示任务的未决结果的 Future
*/
<T> Future<T> submit(Callable<T> task);
/**
提交一个 Runnable 任务用于执行,并返回一个表示该任务的 Future
*/
<T> Future<T> submit(Runnable task, T result);
/**
提交一个 Runnable 任务用于执行,并返回一个表示该任务的 Future
*/
Future<?> submit(Runnable task);
/**
执行给定的任务,当所有任务完成时,返回保持任务状态和结果的 Future 列表
*/
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
throws InterruptedException;
/**
执行给定的任务,当所有任务完成或超时期满时(无论哪个首先发生),返回保持任务状态和结果的 Future 列表
*/
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException;
/**
执行给定的任务,如果某个任务已成功完成(也就是未抛出异常),则返回其结果
*/
<T> T invokeAny(Collection<? extends Callable<T>> tasks)
throws InterruptedException, ExecutionException;
/**
执行给定的任务,如果在给定的超时期满前某个任务已成功完成(也就是未抛出异常),则返回其结果
*/
<T> T invokeAny(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
(3)AbstractExecutorService
为ExecutorService中的函数接口提供了默认实现
public abstract class AbstractExecutorService implements ExecutorService {
//对任务进行了包装为RunnableFuture对象,然后调用了本对象的execute()方法提交任务
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
return new FutureTask<T>(runnable, value);
}
//对任务进行了包装为RunnableFuture对象,然后调用了本对象的execute()方法提交任务
protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
return new FutureTask<T>(callable);
}
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}
/**
对任务进行了包装为RunnableFuture对象,然后调用了本对象的execute()方法提交任务
*/
public <T> Future<T> submit(Runnable task, T result) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task, result);
execute(ftask);
return ftask;
}
/**
ExecutorCompletionService 的submit方法,submit()方法提交任务时,实际上是调用newTaskFor()方法对任务进行了包装为RunnableFuture对象,然后调用了本对象的execute()方法提交任务,并返回异步计算结果对象
*/
public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
/**
* the main mechanics of invokeAny.
*/
private <T> T doInvokeAny(Collection<? extends Callable<T>> tasks,
boolean timed, long nanos)
throws InterruptedException, ExecutionException, TimeoutException {
if (tasks == null)
throw new NullPointerException();
int ntasks = tasks.size();
if (ntasks == 0)
throw new IllegalArgumentException();
// 含有结果的Future队列
ArrayList<Future<T>> futures = new ArrayList<Future<T>>(ntasks);
// 将本对象作为Executor创建ExecutorCompletionService对象
ExecutorCompletionService<T> ecs =
new ExecutorCompletionService<T>(this);
try {
// 记录可能抛出的执行异常
ExecutionException ee = null;
//超时时间
final long deadline = timed ? System.nanoTime() + nanos : 0L;
Iterator<? extends Callable<T>> it = tasks.iterator();
// 确定在主循环之前开始一个任务
futures.add(ecs.submit(it.next()));
--ntasks;
// 记录正在执行的任务数量
int active = 1;
for (;;) {
// 获取并移除下一个将要完成的任务的结果表示,如果没有任何表示则返回null
// 底层调用队列的poll方法(非阻塞)
Future<T> f = ecs.poll();
// 如果没有结果
if (f == null) {
//如果还有剩余的任务,则提交下一个任务
if (ntasks > 0) {
--ntasks;
futures.add(ecs.submit(it.next()));
++active;
}
// 出现这种情况说明,已经有任务完成,并返回结果表示,但是
// 捕获到了异常,则跳出主循环,进行异常的抛出
else if (active == 0)
break;
// 超时获取结果表示
else if (timed) {
f = ecs.poll(nanos, TimeUnit.NANOSECONDS);
if (f == null)
throw new TimeoutException();
nanos = deadline - System.nanoTime();
}
// 阻塞获取结果表示
else
f = ecs.take();
}
//有返回结果
if (f != null) {
--active;
try {
return f.get();
} catch (ExecutionException eex) {
ee = eex;
} catch (RuntimeException rex) {
ee = new ExecutionException(rex);
}
}
}
if (ee == null)
ee = new ExecutionException();
throw ee;
} finally {
// 最后取消所有提交的任务
for (int i = 0, size = futures.size(); i < size; i++)
futures.get(i).cancel(true);
}
}
// 无超时等待的doInvokeAny
public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
throws InterruptedException, ExecutionException {
try {
return doInvokeAny(tasks, false, 0);
} catch (TimeoutException cannotHappen) {
assert false;
return null;
}
}
//超时等待的doInvokeAny
public <T> T invokeAny(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
return doInvokeAny(tasks, true, unit.toNanos(timeout));
}
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
throws InterruptedException {
if (tasks == null)
throw new NullPointerException();
ArrayList<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
// 所有任务是否完成的标志
boolean done = false;
try {
// 对所有任务进行包装,并提交任务,并将返回的结果添加到futures集合中
for (Callable<T> t : tasks) {
RunnableFuture<T> f = newTaskFor(t);
futures.add(f);
execute(f);
}
// 对所有结果进行判断或者阻塞等待结果返回
for (int i = 0, size = futures.size(); i < size; i++) {
Future<T> f = futures.get(i);
// 如果任务没有完成
if (!f.isDone()) {
try {
// 则阻塞等待结果返回
f.get();
//并不让异常外抛
} catch (CancellationException ignore) {
} catch (ExecutionException ignore) {
}
}
}
//所有任务已经完成了(不管是正常完成还是异常完成)
done = true;
return futures;
} finally {
// 如果发生中断异常InterruptedException 则取消已经提交的任务
if (!done)
for (int i = 0, size = futures.size(); i < size; i++)
futures.get(i).cancel(true);
}
}
/*
超时版本的invokeAll
1) 在添加执行任务时超时判断,如果超时则立刻返回futures集合;
2) 每次对结果进行判断时都进行超时判断。
*/
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException {
if (tasks == null)
throw new NullPointerException();
long nanos = unit.toNanos(timeout);
ArrayList<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
boolean done = false;
try {
for (Callable<T> t : tasks)
futures.add(newTaskFor(t));
final long deadline = System.nanoTime() + nanos;
final int size = futures.size();
// Interleave time checks and calls to execute in case
// executor doesn't have any/much parallelism.
for (int i = 0; i < size; i++) {
execute((Runnable)futures.get(i));
nanos = deadline - System.nanoTime();
// 在添加执行任务时超时判断,如果超时则立刻返回futures集合
if (nanos <= 0L)
return futures;
}
for (int i = 0; i < size; i++) {
Future<T> f = futures.get(i);
// 每次对结果进行判断时都进行超时判断
if (!f.isDone()) {
if (nanos <= 0L)
return futures;
try {
f.get(nanos, TimeUnit.NANOSECONDS);
} catch (CancellationException ignore) {
} catch (ExecutionException ignore) {
} catch (TimeoutException toe) {
return futures;
}
// 更新剩余时间
nanos = deadline - System.nanoTime();
}
}
done = true;
return futures;
} finally {
if (!done)
for (int i = 0, size = futures.size(); i < size; i++)
futures.get(i).cancel(true);
}
}
}
(4)ThreadPoolExecutor
public class ThreadPoolExecutor extends AbstractExecutorService {
//线程池的控制状态(用来表示线程池的运行状态(整形的高3位)和运行的worker数量(低29位))
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
//偏移量
private static final int COUNT_BITS = Integer.SIZE - 3;
//最大容量(2^29 - 1)
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;
/**
* 得到运行状态:入参c为ctl的值,~CAPACITY高3位为1低29位全为0,
* 因此运算结果为ctl的高3位, 也就是运行状态
*/
private static int runStateOf(int c) { return c & ~CAPACITY; 、
/**
* 得到有效的线程数:入参c为ctl的值, CAPACITY高3为为0,
* 低29位全为1, 因此运算结果为ctl的低29位, 也就是有效的线程数
*/
private static int workerCountOf(int c) { return c & CAPACITY; }
/**
* 得到ctl的值:高3位的运行状态和低29位的有效线程数进行或运算,
* 组合成一个完成的32位数
*/
private static int ctlOf(int rs, int wc) { return rs | wc; }
// 状态c是否小于s
private static boolean runStateLessThan(int c, int s) {
return c < s;
}
// 状态c是否大于等于s
private static boolean runStateAtLeast(int c, int s) {
return c >= s;
}
// 状态c是否为RUNNING
private static boolean isRunning(int c) {
return c < SHUTDOWN;
}
// 使用CAS增加一个有效的线程
private boolean compareAndIncrementWorkerCount(int expect) {
return ctl.compareAndSet(expect, expect + 1);
}
// 使用CAS减少一个有效的线程
private boolean compareAndDecrementWorkerCount(int expect) {
return ctl.compareAndSet(expect, expect - 1);
}
// 减少一个有效的线程
private void decrementWorkerCount() {
do {} while (! compareAndDecrementWorkerCount(ctl.get()));
}
// 阻塞队列
private final BlockingQueue<Runnable> workQueue;
// 可重入锁
private final ReentrantLock mainLock = new ReentrantLock();
// 存放工作线程
private final HashSet<Worker> workers = new HashSet<Worker>();
// 终止条件
private final Condition termination = mainLock.newCondition();
// 最大线程池容量
private int largestPoolSize;
// 已完成任务数量
private long completedTaskCount;
// 线程工厂
private volatile ThreadFactory threadFactory;
// 拒绝执行处理器
private volatile RejectedExecutionHandler handler;
// 线程等待运行时间
private volatile long keepAliveTime;
// 是否运行核心线程超时
private volatile boolean allowCoreThreadTimeOut;
// 核心池的大小
private volatile int corePoolSize;
// 最大线程池大小
private volatile int maximumPoolSize;
// 默认拒绝执行处理器
private static final RejectedExecutionHandler defaultHandler =
new AbortPolicy();
private static final RuntimePermission shutdownPerm =
new RuntimePermission("modifyThread");
/* The context to be used when executing the finalizer, or null. */
private final AccessControlContext acc;
/**
* Worker类,每个Worker包含一个线程、一个初始任务、一个任务计算器
*/
private final class Worker
extends AbstractQueuedSynchronizer
implements Runnable
{
/**
* This class will never be serialized, but we provide a
* serialVersionUID to suppress a javac warning.
*/
private static final long serialVersionUID = 6138294804551838833L;
// Worker对应的线程
final Thread thread;
// 运行的初始任务
Runnable firstTask;
// 每个线程的任务计数器
volatile long completedTasks;
/**
构造器
*/
Worker(Runnable firstTask) {
// 禁止中断,直到runWorker
setState(-1);
// 设置为初始任务
this.firstTask = firstTask;
// 使用当前线程池的线程工厂创建一个线程
this.thread = getThreadFactory().newThread(this);
}
/** Delegates main run loop to outer runWorker */
public void run() {
// 将主运行循环委托给外部runWorker
runWorker(this);
}
/*
* 通过AQS的同步状态来实现锁机制。state为0时代表锁未被获取(解锁状态),
* state为1时代表锁已经被获取(加锁状态)。
*/
protected boolean isHeldExclusively() {
return getState() != 0;
}
// 尝试获取锁
protected boolean tryAcquire(int unused) {
// 使用CAS尝试将state设置为1,即尝试获取锁
if (compareAndSetState(0, 1)) {
// 成功将state设置为1,则当前线程拥有独占访问权
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
// 尝试释放锁
protected boolean tryRelease(int unused) {
// 释放独占访问权:即将独占访问线程设为null
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(); }
// 如果线程启动了,则进行中断
void interruptIfStarted() {
Thread t;
if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
}
}
}
}
/*
如果线程池当前状态大于等于目标状态或者成功修改运行状态退出循环,否则修改线程池状态
*/
private void advanceRunState(int targetState) {
for (;;) {
int c = ctl.get();
if (runStateAtLeast(c, targetState) ||
ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c))))
break;
}
}
/**
尝试终止线程池
主要在移除Worker后会调用此方法。首先进行一些状态的校验,如果通过校验,则在加锁的条件下,使用CAS将运行状态设为TERMINATED,有效线程数设为0。
*/
final void tryTerminate() {
for (;;) {
int c = ctl.get();
/*
只有当前状态为STOP 或者 SHUTDOWN并且队列为空,才会尝试整理并终止
1: 当前状态为RUNNING,则不尝试终止,直接返回
2: 当前状态为TIDYING或TERMINATED,代表有其他线程正在执行终止,直接返回
3: 当前状态为SHUTDOWN 并且 workQueue不为空,则不尝试终止,直接返回
*/
if (isRunning(c) ||
runStateAtLeast(c, TIDYING) ||
(runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
return;
// 走到这代表线程池可以终止(通过上面的校验)
// 如果此时有效线程数不为0, 将中断一个空闲的Worker,以确保关闭信号传播
if (workerCountOf(c) != 0) { // Eligible to terminate
interruptIdleWorkers(ONLY_ONE);
return;
}
// 加锁,终止线程池
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// 使用CAS将ctl的运行状态设置为TIDYING,有效线程数设置为0
if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
try {
// 供用户重写的terminated方法,默认为空
terminated();
} finally {
// 将ctl的运行状态设置为TERMINATED,有效线程数设置为0
ctl.set(ctlOf(TERMINATED, 0));
termination.signalAll();
}
return;
}
} finally {
mainLock.unlock();
}
// else retry on failed CAS
}
}
/**
检查方法调用者是否有权限中断Worker线程。
*/
private void checkShutdownAccess() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkPermission(shutdownPerm);
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker w : workers)
security.checkAccess(w.thread);
} finally {
mainLock.unlock();
}
}
}
/**
关于interruptIdleWorkers和interruptWorkers,因为Worker线程具备锁的功能,因此可以通过tryLock来判断Worker线程是否处于空闲状态,这是两个方法的区别所在。interruptIdleWorkers会调用tryLock。
*/
//中断正在运行的任务线程,即使处于活动状态
private void interruptWorkers() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker w : workers)
w.interruptIfStarted();
} finally {
mainLock.unlock();
}
}
/**
中断正在运行的任务线程,即使处于活动状态
*/
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()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
} finally {
w.unlock();
}
}
if (onlyOne)
break;
}
} finally {
mainLock.unlock();
}
}
private void interruptIdleWorkers() {
interruptIdleWorkers(false);
}
private static final boolean ONLY_ONE = true;
/**
饱和策略拒绝任务
*/
final void reject(Runnable command) {
handler.rejectedExecution(command, this);
}
void onShutdown() {
}
/**
判断一下线程池的状态
*/
final boolean isRunningOrShutdown(boolean shutdownOK) {
int rs = runStateOf(ctl.get());
return rs == RUNNING || (rs == SHUTDOWN && shutdownOK);
}
/**
将任务队列放到新列表。 但是,如果队列是DelayQueue或其他类型的队列,但poll或drainTo可能无法删除过期的元素,则会逐个删除它们,放到新列表
*/
private List<Runnable> drainQueue() {
BlockingQueue<Runnable> q = workQueue;
ArrayList<Runnable> taskList = new ArrayList<Runnable>();
q.drainTo(taskList);
if (!q.isEmpty()) {
for (Runnable r : q.toArray(new Runnable[0])) {
if (q.remove(r))
taskList.add(r);
}
}
return taskList;
}
/**
*/
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) {
// 获取线程池控制状态
int c = ctl.get();
// 获取状态
int rs = runStateOf(c);
// 检查状态大于等于SHUTDOWN,初始的ctl为RUNNING,小于SHUTDOWN
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
for (;;) {
int wc = workerCountOf(c);
// worker数量大于等于最大容量或 worker数量大于等于核心线程池大小或者最大线程池大小
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
//比较并增加worker的数量
if (compareAndIncrementWorkerCount(c))
break retry;
c = ctl.get(); // Re-read ctl
// 此次的状态与上次获取的状态不相同,则跳过剩余部分,继续循环
if (runStateOf(c) != rs)
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
}
// worker开始标识
boolean workerStarted = false;
// worker被添加标识
boolean workerAdded = false;
Worker w = null;
try {
w = new Worker(firstTask);
// 获取worker对应的线程
final Thread t = w.thread;
if (t != null) {
// 线程池锁
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// 线程池的运行状态
int rs = runStateOf(ctl.get());
//判断线程池状态
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
// 将worker添加到worker集合
workers.add(w);
// 获取worker集合的大小
int s = workers.size();
// 如果队列大小大于largestPoolSize,重新设置largestPoolSize
if (s > largestPoolSize)
largestPoolSize = s;
// 设置worker已被添加标识
workerAdded = true;
}
} finally {
// 释放锁
mainLock.unlock();
}
// worker被添加
if (workerAdded) {
t.start();
workerStarted = true;
}
}
} finally {
// worker没有开始
if (! workerStarted)
// 添加worker失败
addWorkerFailed(w);
}
return workerStarted;
}
/**
如果任务启动失败workers的Workder删除,有效线程数减1,并且尝试将线程池状态置为TERMINATED
*/
private void addWorkerFailed(Worker w) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
if (w != null)
workers.remove(w);
decrementWorkerCount();
tryTerminate();
} finally {
mainLock.unlock();
}
}
/**
在worker退出时调用到的钩子函数
*/
private void processWorkerExit(Worker w, boolean completedAbruptly) {
//如果工作线程因异常而终止,线程池有效线程数一定减1
if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
decrementWorkerCount();
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
//从Woker获取一共完成的任务数
completedTaskCount += w.completedTasks;
//移除woker
workers.remove(w);
} finally {
mainLock.unlock();
}
//尝试终止线程池
tryTerminate();
int c = ctl.get();
//如果线程池状态小于STOP
if (runStateLessThan(c, STOP)) {
//如果线程是异常退出重新创建一个worker
if (!completedAbruptly) {
//如果worker线程不是异常退出,看是否配置allowCoreThreadTimeOut参数获取最小值min,如果min等于0并且workQueue不为空 min赋值1,如果有效线程数大于等于min直接返回
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
if (min == 0 && ! workQueue.isEmpty())
min = 1;
if (workerCountOf(c) >= min)
return; // replacement not needed
}
//如果有效线程数 小于min的话添加worker
addWorker(null, false);
}
}
/**
*/
private Runnable getTask() {
boolean timedOut = false; // Did the last poll() time out?
for (;;) {
// 获取线程池控制状态
int c = ctl.get();
// 运行的状态
int rs = runStateOf(c);
// 大于等于SHUTDOWN并且(大于等于STOP或者worker阻塞队列为空)
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
// 减少worker的数量
decrementWorkerCount();
// 返回null,不执行任务
return null;
}
// 获取worker数量
int wc = workerCountOf(c);
// 是否允许coreThread超时或者workerCount大于核心大小
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
// worker数量大于maximumPoolSize
//与 workerCount大于1或者worker阻塞队列为空(在阻塞队列不为空时,需要保证至少有一个wc)
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
// 比较并减少workerCount
if (compareAndDecrementWorkerCount(c))
// 返回null,不执行任务
return null;
continue;
}
try {
// 等待指定时间还是一直等待,直到有元素
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;
// 等待指定时间后,没有获取元素,则超时
timedOut = true;
} catch (InterruptedException retry) {
// 抛出了被中断异常,重试,没有超时
timedOut = false;
}
}
}
//用来执行任务
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
// 释放锁(设置state为0,允许中断)
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
// 任务不为null或者阻塞队列还存在任务
while (task != null || (task = getTask()) != null) {
w.lock();
// 线程池的运行状态至少应该高于STOP
// 线程被中断
// 再次检查,线程池的运行状态至少应该高于STOP
// wt线程(当前线程)没有被中断
// 中断wt线程(当前线程)
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
try {
// 在执行任务之前调用钩子函数
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(task, thrown);
}
} finally {
task = null;
// 增加给worker完成的任务数量
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
// 处理完成后,调用钩子函数
processWorkerExit(w, completedAbruptly);
}
}
// Public constructors and methods
/**
构造器一会单独讲解
*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
/**
总体节奏:
1. 如果运行的线程小于corePoolSize,则尝试使用用户定义的Runnalbe对象创建一个新的线程,调用addWorker函数会原子性的检查runState和workCount,通过返回false来防止在不应该添加线程时添加了线程
2. 如果一个任务能够成功入队列,在添加一个线城时仍需要进行双重检查(因为在前一次检查后该线程死亡了),或者当进入到此方法时,线程池已经shutdown了,所以需要再次检查状态,若有必要,当停止时还需要回滚入队列操作,或者当线程池没有线程时需要创建一个新线程
3. 如果无法入队列,那么需要增加一个新线程,如果此操作失败,那么就意味着线程池已经shutown或者已经饱和了,所以拒绝任务
*/
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
// worker数量小于corePoolSize
if (workerCountOf(c) < corePoolSize) {
// 添加worker
if (addWorker(command, true))
// 成功则返回
return;
// 不成功则再次获取线程池控制状态
c = ctl.get();
}
// 线程池处于RUNNING状态,将命令(用户自定义的Runnable对象)添加进workQueue队列
if (isRunning(c) && workQueue.offer(command)) {
// 再次检查,获取线程池控制状态
int recheck = ctl.get();
// 线程池不处于RUNNING状态,将命令从workQueue队列中移除
if (! isRunning(recheck) && remove(command))
// 拒绝执行命令
reject(command);
// worker数量等于0
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
// 添加worker失败
else if (!addWorker(command, false))
reject(command);
}
/**
假如队列里面有任务没有处理完 会继续处理
*/
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// 检查shutdown权限
checkShutdownAccess();
// 设置线程池控制状态为SHUTDOWN
advanceRunState(SHUTDOWN);
// 中断空闲worker
interruptIdleWorkers();
// 调用shutdown钩子函数
onShutdown(); // hook for ScheduledThreadPoolExecutor
} finally {
mainLock.unlock();
}
// 尝试终止
tryTerminate();
}
/**
假如队列里面有任务没有处理完 也不能继续处理,哪怕线程正在执行任务。
注意:即便shutdownNow即便会中断正在执行任务的线程,不代表你的任务一定会挂:如果提交的任务里面的代码没有对线程中断敏感的逻辑的话,线程中断也不会发生什么。
*/
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;
}
public boolean isShutdown() {
return ! isRunning(ctl.get());
}
public boolean isTerminating() {
int c = ctl.get();
return ! isRunning(c) && runStateLessThan(c, TERMINATED);
}
public boolean isTerminated() {
return runStateAtLeast(ctl.get(), TERMINATED);
}
//等待一定的时间线程池的状态是否大于等于TERMINATED
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))
return true;
if (nanos <= 0)
return false;
nanos = termination.awaitNanos(nanos);
}
} finally {
mainLock.unlock();
}
}
/**
调用shutdown方法
*/
protected void finalize() {
SecurityManager sm = System.getSecurityManager();
if (sm == null || acc == null) {
shutdown();
} else {
PrivilegedAction<Void> pa = () -> { shutdown(); return null; };
AccessController.doPrivileged(pa, acc);
}
}
public void setThreadFactory(ThreadFactory threadFactory) {
if (threadFactory == null)
throw new NullPointerException();
this.threadFactory = threadFactory;
}
public ThreadFactory getThreadFactory() {
return threadFactory;
}
/**
设置饱和策略
*/
public void setRejectedExecutionHandler(RejectedExecutionHandler handler) {
if (handler == null)
throw new NullPointerException();
this.handler = handler;
}
public RejectedExecutionHandler getRejectedExecutionHandler() {
return handler;
}
/**
设置核心线程数大小
*/
public void setCorePoolSize(int corePoolSize) {
if (corePoolSize < 0)
throw new IllegalArgumentException();
int delta = corePoolSize - this.corePoolSize;
this.corePoolSize = corePoolSize;
//如果有效线程数大于corePoolSize,中断所有空闲的worker线程
if (workerCountOf(ctl.get()) > corePoolSize)
interruptIdleWorkers();
//有效线程数小于corePoolSize情况
else if (delta > 0) {
int k = Math.min(delta, workQueue.size());
//创建新的worker处理任务队列里面的任务
while (k-- > 0 && addWorker(null, true)) {
if (workQueue.isEmpty())
break;
}
}
}
/**
提前把核心线程初始化好
*/
public boolean prestartCoreThread() {
return workerCountOf(ctl.get()) < corePoolSize &&
addWorker(null, true);
}
/**
确保提前启动核心线程
*/
void ensurePrestart() {
int wc = workerCountOf(ctl.get());
if (wc < corePoolSize)
addWorker(null, true);
else if (wc == 0)
addWorker(null, false);
}
/**
提前启动全部线程
*/
public int prestartAllCoreThreads() {
int n = 0;
while (addWorker(null, true))
++n;
return n;
}
/**
核心线程也会被中断
核心线程超时控制标志位:用于标识是否keepAliveTime的效果同样作用在核心线程上
*/
public void allowCoreThreadTimeOut(boolean value) {
if (value && keepAliveTime <= 0)
throw new IllegalArgumentException("Core threads must have nonzero keep alive times");
if (value != allowCoreThreadTimeOut) {
allowCoreThreadTimeOut = value;
if (value)
interruptIdleWorkers();
}
}
/**
设置最大线程数
*/
public void setMaximumPoolSize(int maximumPoolSize) {
if (maximumPoolSize <= 0 || maximumPoolSize < corePoolSize)
throw new IllegalArgumentException();
this.maximumPoolSize = maximumPoolSize;
if (workerCountOf(ctl.get()) > maximumPoolSize)
interruptIdleWorkers();
}
/**
设置比核心线程多出来的线程的存活时间
*/
public void setKeepAliveTime(long time, TimeUnit unit) {
if (time < 0)
throw new IllegalArgumentException();
if (time == 0 && allowsCoreThreadTimeOut())
throw new IllegalArgumentException("Core threads must have nonzero keep alive times");
long keepAliveTime = unit.toNanos(time);
long delta = keepAliveTime - this.keepAliveTime;
this.keepAliveTime = keepAliveTime;
if (delta < 0)
interruptIdleWorkers();
}
/* User-level queue utilities */
public BlockingQueue<Runnable> getQueue() {
return workQueue;
}
/**
将任务从workQueue队列中移除
*/
public boolean remove(Runnable task) {
boolean removed = workQueue.remove(task);
tryTerminate(); // In case SHUTDOWN and now empty
return removed;
}
/**
清除任务:
尝试从工作队列移除所有已取消的 Future 任务。此方法可用作存储回收操作,它对功能没有任何影响。
取消的任务不会再次执行,但是它们可能在工作队列中累积,直到worker线程主动将其移除。
调用此方法将试图立即移除它们。但是,如果出现其他线程的干预,那么此方法移除任务将失败。
*/
public void purge() {
final BlockingQueue<Runnable> q = workQueue;
try {
Iterator<Runnable> it = q.iterator();
while (it.hasNext()) {
Runnable r = it.next();
if (r instanceof Future<?> && ((Future<?>)r).isCancelled())
it.remove();
}
} catch (ConcurrentModificationException fallThrough) {
// Take slow path if we encounter interference during traversal.
// Make copy for traversal and call remove for cancelled entries.
// The slow path is more likely to be O(N*N).
for (Object r : q.toArray())
if (r instanceof Future<?> && ((Future<?>)r).isCancelled())
q.remove(r);
}
tryTerminate(); // In case SHUTDOWN and now empty
}
/* Statistics */
/**
返回当前线程数量大小
*/
public int getPoolSize() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// Remove rare and surprising possibility of
// isTerminated() && getPoolSize() > 0
return runStateAtLeast(ctl.get(), TIDYING) ? 0
: workers.size();
} finally {
mainLock.unlock();
}
}
/**
获取活跃的线程数
*/
public int getActiveCount() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
int n = 0;
for (Worker w : workers)
if (w.isLocked())
++n;
return n;
} finally {
mainLock.unlock();
}
}
/**
获取线程池最大的数
*/
public int getLargestPoolSize() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
return largestPoolSize;
} finally {
mainLock.unlock();
}
}
/**
获取任务的个数
*/
public long getTaskCount() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
long n = completedTaskCount;
for (Worker w : workers) {
n += w.completedTasks;
if (w.isLocked())
++n;
}
return n + workQueue.size();
} finally {
mainLock.unlock();
}
}
/**
完成的任务数
*/
public long getCompletedTaskCount() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
long n = completedTaskCount;
for (Worker w : workers)
n += w.completedTasks;
return n;
} finally {
mainLock.unlock();
}
}
/* Extension hooks */
/**
* 默认空,需要自己重写。执行任务前调用
*/
protected void beforeExecute(Thread t, Runnable r) { }
/**
默认空,需要自己重写.执行任务后调用
*/
protected void afterExecute(Runnable r, Throwable t) { }
/**
调用者运行策略。该策略实现了一种调节机制,该策略既不会抛弃任务,也不会抛出异常,而是将某些任务回退到调用者(调用线程池执行任务的主线程),从而降低新任务的流程
*/
public static class CallerRunsPolicy implements RejectedExecutionHandler {
public CallerRunsPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
r.run();
}
}
}
/**
中止策略。默认的饱和策略,抛出未检查的RejectedExecutionException。调用者可以捕获这个异常,然后根据需求编写自己的处理代码。
*/
public static class AbortPolicy implements RejectedExecutionHandler {
public AbortPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException("Task " + r.toString() +
" rejected from " +
e.toString());
}
}
/**
抛弃策略。当新提交的任务无法保存到队列中等待执行时,该策略会悄悄抛弃该任务。
*/
public static class DiscardPolicy implements RejectedExecutionHandler {
public DiscardPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
}
}
/**
抛弃最旧的策略。当新提交的任务无法保存到队列中等待执行时,则会抛弃下一个将被执行的任务,然后尝试重新提交新的任务。(如果工作队列是一个优先队列,那么“抛弃最旧的”策略将导致抛弃优先级最高的任务,因此最好不要将“抛弃最旧的”策略和优先级队列放在一起使用)。
*/
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
public DiscardOldestPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
e.getQueue().poll();
e.execute(r);
}
}
}
}
(1)重点关注-构造器:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
corePoolSize:线程池核心线程数量
当提交一个任务到线程池的时候,线程池会创建一个线程来执行执行任务,即使有其他空闲的线程存在,直到线程数达到corePoolSize时不再创建,这时候会把提交的新任务放入到阻塞队列中,如果调用了线程池的preStartAllCoreThreads方法,则会在创建线程池的时候初始化出来核心线程;
maximumPoolSize:线程池最大线程数量
如果阻塞队列已经满了,同时已经创建的线程数小于最大线程数的话,那么会创建新的线程来处理阻塞队列中的任务;
keepAliverTime:当活跃线程数大于核心线程数时,空闲的多余线程最大存活时间。
指的是工作线程空闲之后继续存活的时间,默认情况下,这个参数只有线程数大于corePoolSize的时候才会起作用,即当线程池中的线程数目大于corePoolSize的时候,如果某一个线程的空闲时间达到keepAliveTime,那么这个线程是会被终止的,直到线程池中的线程数目不大于corePoolSize;如果调用allowCoreThreadTimeOut的话,在线程池中线程数量不大于corePoolSize的时候,keepAliveTime参数也可以起作用的,知道线程数目为0为止;
unit:存活时间的单位
workQueue:存放任务的队列
用于存储等待执行的任务,有四种阻塞队列类型,ArrayBlockingQueue(基于数组的有界阻塞队列)、LinkedBlockingQueue(基于链表结构的阻塞队列)、SynchronousQueue(不存储元素的阻塞队列)、PriorityBlockingQueue(具有优先级的阻塞队列);
threadFactory:用于创建线程的线程工厂;
handler:超出线程范围和队列容量的任务的处理程序
当阻塞队列满了,且没有空闲线程的情况下,也就是说这个时候,线程池中的线程数目已经达到了最大线程数量,处于饱和状态,那么必须采取一种策略来处理新提交的任务,我们可以自己定义处理策略,也可以使用系统已经提供给我们的策略,默认配置是AbortPolicy。
先来看看系统为我们提供的4种饱和策略,AbortPolicy(直接抛出异常)、CallerRunsPolicy(由提交任务的线程自己来执行这个任务)、DiscardOldestPolicy(丢弃阻塞队列中最近的一个任务,并执行当前任务)、Discard(直接丢弃);
(2)重点关注-execute方法:
其实也是三个步骤:
活动线程小于corePoolSize的时候创建新的线程;
活动线程大于corePoolSize时都是先加入到任务队列当中;
任务队列满了再去启动新的线程,如果线程数达到最大值就拒绝任务。
<1>:首先判断当前线程池中的线程数量是否小于corePoolSize,如果小于的话,则直接通过addWorker方法创建一个新的Worker对象来执行我们当前的任务;
<2>:如果说当前线程池中的线程数量大于corePoolSize的话,那么会尝试将当前任务添加到阻塞队列中,然后第二次检查线程池的状态,如果线程池不在Running状态的话,会将刚刚添加到阻塞队列中的任务移出,同时拒绝当前任务请求;如果第二次检查发现当前线程池处于Running状态的话,那么会查看当前线程池中的工作线程数量是否为0,如果为0的话,就会通过addWorker方法创建一个Worker对象出来处理阻塞队列中的任务;
<3>:如果原先线程池就不处于Running状态或者我们刚刚将当前任务添加到阻塞队列的时候出现错误的话,那么会去尝试通过addWorker创建新的Worker来处理当前任务,如果添加失败的话,则拒绝当前任务请求;
七、思考几个问题:
(1)将任务添加到线程池,运行线程(submit与execute的区别)
可以调用submit或者execute方法,两者最大的区别在于。
调用submit方法的话,我们可以传入一个实现Callable接口的对象,进而能在当前任务执行结束之后通过Future对象获得任务的返回值,submit内部实际上还是执行的execute方法;
而调用execute方法的话,是不能获得任务执行结束之后的返回值的;此外,调用submit方法的话是可以抛出异常的,但是调用execute方法的话,异常在其内部得到了消化,也就是说异常在其内部得到了处理,不会向外传递的;因为submit方法最终也是会执行execute方法的,因此我们只需要了解execute方法就可以了。
(2)线程池的关闭
需要用到两个方法,shutdown和shutdownNow,他们都是位于ThreadPoolExecutor里面的,对于shutdown的话,他会将线程池状态切换成Shutdown,此时是不会影响对阻塞队列中任务执行的,但是会拒绝执行新加进来的任务,同时会回收闲置的Worker;而shutdownNow方法会将线程池状态切换成Stop,此时既不会再去处理阻塞队列里面的任务,也不会去处理新加进来的任务,同时会回收所有Worker;
(3)线程池如何做到重用线程
举个栗子:
假如coreSize=3,maxSize=10,当前存在线程数是6。
(注意,存在的这6个线程,并不是你执行ExecuteService.execute/submit时的参数,
而是为了执行execute/submit的参数所启动的“内部线程”。
这个“内部线程”其实是通过ThreadPoolExecutor的ThreadFactory参数生成的线程,
而“execute/submit的参数”是执行在这些“内部线程”里面的。)
存在这6个“内部线程”,都访问同一个队列,
从队列中去取任务执行(任务就是通过execute/submit提交的Runnable参数),
当任务充足时,6个“内部线程”都持续执行。重点是没有任务时怎么办?
没有任务时,这6个“内部线程”都会做下面判断:
如果poolSize > coreSize,那就从队列里取任务,
当过了keepaliveTime这么长时间还没有得到任务的话,
当前这个“内部线程”就会结束(使用的是BlockingQueue.poll方法)。
如果poolSize <= coreSize,那就以“阻塞”的方式,去从队列里取任务,
当得到任务后,就继续执行。这样的话,这个线程就不会结束掉。
如果没有任务可以继续执行了,最后只剩下coreSize那么多的“内部线程”留在线程池里,等待重用。
源码去分析:
首先是runWoker方法源码:
//用来执行任务
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
// 释放锁(设置state为0,允许中断)
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
// 任务不为null或者阻塞队列还存在任务
while (task != null || (task = getTask()) != null) {
w.lock();
// 线程池的运行状态至少应该高于STOP
// 线程被中断
// 再次检查,线程池的运行状态至少应该高于STOP
// wt线程(当前线程)没有被中断
// 中断wt线程(当前线程)
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
try {
// 在执行任务之前调用钩子函数
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(task, thrown);
}
} finally {
task = null;
// 增加给worker完成的任务数量
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
// 处理完成后,调用钩子函数
processWorkerExit(w, completedAbruptly);
}
}
然后是getTask源码
/*
* 依赖当前的配置阻塞或等待指定时间获取一个任务,如果在发生以下情况那么
* 当前的worker必须退出,则返回null
* 1. 当前线程数超过了最大线程数(可能由于动态修改了最大线程数)
* 2. 线程池状态未STOP
* 3. 线程池状态为SHUTDOWN 并且任务队列未空
* 4. 当前线程等待获取任务超时,并且要释放(比如设置了核心线程数可以超时或者线程数>核心线程数)
*
* @return 返回下一个任务,如果当前worker必须退出,返回null,并对线程数-1
*/
private Runnable getTask() {
boolean timedOut = false; // Did the last poll() time out?
for (;;) {
// 获取线程池控制状态
int c = ctl.get();
// 运行的状态
int rs = runStateOf(c);
// 大于等于SHUTDOWN并且(大于等于STOP或者worker阻塞队列为空)
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
// 减少worker的数量
decrementWorkerCount();
// 返回null,不执行任务
return null;
}
// 获取worker数量
int wc = workerCountOf(c);
// 是否允许coreThread超时或者workerCount大于核心大小
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
// worker数量大于maximumPoolSize
//与 workerCount大于1或者worker阻塞队列为空(在阻塞队列不为空时,需要保证至少有一个wc)
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
// 比较并减少workerCount
if (compareAndDecrementWorkerCount(c))
// 返回null,不执行任务
return null;
continue;
}
//拿内部的队列,重用关键
try {
// 等待指定时间还是一直等待,直到有元素
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;
// 等待指定时间后,没有获取元素,则超时
timedOut = true;
} catch (InterruptedException retry) {
// 抛出了被中断异常,重试,没有超时
timedOut = false;
}
}
}
重用线程的工作其实是在runWorker和getTask里面实现的,runWorker会嵌套一个while的循环,getTask从阻塞队列中取任务。
每当一个任务执行完毕,会从头开始进行下一次的循环,从而实现线程的复用。
我们从runWorker到getTask的视角来看。
存在两个for死循环嵌套的,他会不断的从阻塞对列里面取出需要执行的任务,返回给我们的runWorker方法里面,而在runWorker方法里面只要getTask返回的任务不是空就会执行该任务的run方法来处理它,这样一直执行下去,直到getTask返回空为止,此时的情况就是阻塞队列里面没有任务了,这样一个线程处理完一个任务之后接着再处理阻塞队列中的另一个任务,当然在线程池中的不同线程是可以并发处理阻塞队列中的任务的,最后在阻塞队列内部不存在任务的时候会去判断是否需要回收Worker对象,其实Worker对象的个数就是线程池中线程的个数,至于什么情况才需要回收,上面已经说了,就是四种饱和情况了。
(4)线程池的三个缓存队列
workQueue 线程池所使用的缓冲队列。缓冲队列有三种通用策略:
1)直接提交。
工作队列的默认选项是 SynchronousQueue,它将任务直接提交给线程而不保持它们。
在此,如果不存在可用于立即运行任务的线程,则试图把任务加入队列将失败,因此会构造一个新的线程。
此策略可以避免在处理可能具有内部依赖性的请求集时出现锁。直接提交通常要求无界 maximumPoolSizes 以避免拒绝新提交的任务。当命令以超过队列所能处理的平均数连续到达时,此策略允许无界线程具有增长的可能性;
2) 无界队列
使用无界队列(例如,不具有预定义容量的 LinkedBlockingQueue)将导致在所有 corePoolSize 线程都忙时,新任务将在队列中等待。这样,创建的线程数量就不会超过 corePoolSize。(因此,maximumPoolSize 的值也就无效了。)
当每个任务完全独立于其他任务,即任务执行互不影响时,适合于使用无界队列;例如,在 Web 页服务器中。这种排队可用于处理瞬态突发请求,当命令以超过队列所能处理的平均数连续到达时,此策略允许无界线程具有增长的可能性;
3)有界队列
当使用有限的 maximumPoolSizes 时,有界队列(如 ArrayBlockingQueue)有助于防止资源耗尽,但是可能较难调整和控制。(所以不推荐)
队列大小和最大池大小可能需要相互折衷:使用大型队列和小型池可以最大限度地降低 CPU 使用率、操作系统资源和上下文切换开销,但是可能导致人工降低吞吐量。如果任务频繁阻塞(例如,如果它们是 I/O 边界),则系统可能为超过您许可的更多线程安排时间。使用小型队列通常要求较大的池大小,CPU 使用率较高,但是可能遇到不可接受的调度开销,这样也会降低吞吐量.
(5)如何选择线程池大小
1)从以下几个角度分析:
- 任务的性质:CPU密集型任务、IO密集型任务、混合型任务。
- 任务的优先级:高、中、低。
- 任务的执行时间:长、中、短。
- 任务的依赖性:是否依赖其他系统资源,如数据库连接等。
性质不同的任务可以交给不同规模的线程池执行。
对于不同性质的任务来说,CPU密集型任务应配置尽可能小的线程,如配置CPU个数+1的线程数,IO密集型任务应配置尽可能多的线程,因为IO操作不占用CPU,不要让CPU闲下来,应加大线程数量,如配置两倍CPU个数+1,而对于混合型的任务,如果可以拆分,拆分成IO密集型和CPU密集型分别处理,前提是两者运行的时间是差不多的,如果处理时间相差很大,则没必要拆分了。
2)公式:
最佳线程数目 = ((线程等待时间+线程CPU时间)/线程CPU时间 )* CPU数目
结论:
线程等待时间所占比例越高,需要越多线程。线程CPU时间所占比例越高,需要越少线程。
3)问题:
高并发、任务执行时间短的业务怎样使用线程池?并发不高、任务执行时间长的业务怎样使用线程池?并发高、业务执行时间长的业务怎样使用线程池?
1-高并发、任务执行时间短的业务
线程池线程数可以设置为CPU核数+1,减少线程上下文的切换
2-并发不高、任务执行时间长的业务要区分开看:
a)假如是业务时间长集中在IO操作上,也就是IO密集型的任务,因为IO操作并不占用CPU,所以不要让所有的CPU闲下来,可以适当加大线程池中的线程数目,让CPU处理更多的业务
b)假如是业务时间长集中在计算操作上,也就是计算密集型任务,这个就没办法了,和(1)一样吧,线程池中的线程数设置得少一些,减少线程上下文的切换
3-并发高、业务执行时间长,解决这种类型任务的关键不在于线程池而在于整体架构的设计
看看这些业务里面某些数据是否能做缓存是第一步,增加服务器是第二步,至于线程池的设置,设置参考(2)。最后,业务执行时间长的问题,也可能需要分析一下,看看能不能使用中间件对任务进行拆分和解耦。
4)为什么IO不占用CPU?
IO所需要的CPU资源非常少。大部分工作是分派给DMA(芯片)完成的。
计算机硬件上使用DMA来访问磁盘等IO,也就是请求发出后,CPU就不再管了,直到DMA处理器完成任务,再通过中断告诉CPU完成了。所以,单独的一个IO时间,对CPU的占用是很少的,阻塞了就更不会占用CPU了,因为程序都不继续运行了,CPU时间交给其它线程和进程了。虽然IO不会占用大量的CPU时间,但是非常频繁的IO还是会非常浪费CPU时间的,所以面对大量IO的任务,有时候是需要算法来合并IO,或者通过cache来缓解IO压力的。
5)设计建议:
以上的估算方式所得值,只是一个大概值。具体的线程数还是要依赖压力测试去决定。只不过这个估算值可以帮我们省下一部分功夫。
(6)多线程一定比单线程快吗?
肯定不是啦!
比如Redis就是单线程的,但它却非常高效。
从线程这个角度来看,部分原因在于:多线程带来线程上下文切换开销,单线程就没有这种开销。
当然“Redis很快”更本质的原因在于:Redis基本都是内存操作,这种情况下单线程可以很高效地利用CPU。而多线程适用场景一般是:存在相当比例的IO和网络操作。
(7)阿姆达尔定律(Amdahl)–定义了串行系统并行化后加速比的计算公式与理论上限
Amdahl官方文档
Amdahl’s law (or Amdahl’s argument[1]) is a formula which gives the theoretical speedup in latency of the execution of a task at fixed workload that can be expected of a system whose resources are improved.
Amdahl是一个公式,它给出了在固定工作负载下执行任务的延迟的理论加速,这可以预期资源得到改善的系统。
阿姆达尔定律是计算机并行重要的定律。定义了串行系统并行化后的加速比的计算公式和理论上限。
在性能调优领域,我们利用此定律有助于我们解决或者缓解性能瓶颈问题。
阿姆达尔定律的模型阐释了我们现实生产中串行资源争用时候的现象。如下图模型,一个系统中,不可避免有一些资源必须串行访问,这限制了我们的加速比,即使我们增加了并发数(横轴),但取得效果并不理想,难以获得线性扩展能力(图中直线)。
但是根据Amdahl定律的演变,根据执行它的处理器的数量,执行程序的延迟的理论加速。加速受程序序列部分的限制。例如,如果95%的程序可以并行化,那么使用并行计算的理论最大加速比将是20倍。
在并行计算中,使用多个处理器的程序的加速比受限制于程序串行部分的执行时间。例如,如果一个程序使用一个CPU核执行需要20小时,其中部分代码只能串行,需要执行1个小时,其他19小时的代码执行可以并行,那么,不考虑有多少CPU可用来并行执行程序,最小执行时间不会小于1小时(串行工作的部分),因此加速比被限制为最多20倍(20/1)。
加速比越高,证明优化效果越明显。
加速比 = 优化之前系统耗时 / 优化后系统耗时
对于Amdahl,我们可以利用它进行对我们的系统的优化进行评估、优化后的指标定量以及指导CPU利用的可扩展设计。
结语
以上就是今天线程池讨论的所有内容,往后希望讨论线程池的优化设计、随处可见的线程在我们大型应用中的设计问题等等…欢迎来交流讨论。
更多内容,可以访问JackFrost的博客