线程池
- 线程池任务,线程是如何选择的 ?
是阻塞队列选择一个消费者
- 线程空闲时,操作系统是否会调度?
阻塞
线程池状态
状态转换 | 状态转换方式 |
---|---|
RUNNING -> SHUTDOWN | 当调用了线程池的shutdown方法时,或者当finalize方法被隐式调用后(该方法内部会调用shutdown方法) |
RUNNING,SHUTDOWN -> STOP | 当调用了线程池的shutdownNow方法时 |
SHUTDOWN -> TIDYING | 在线程池与阻塞队列均变为空时 |
STOP -> TIDYING | 在线程池变为空时 |
TIDYING->TERMINATED | 在terminated方法被执行完毕时 |
// ctl:高三位表示线程池运行状态,低29位表示线程池线程运行数量
// 一个变量存储两个值的好处是不必费心思(比如加锁)去维护两个状态的一致性
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
// 获取线程池当前的运行状态(~:按位取反,即0变成1,1变成0。)
private static int runStateOf(int c) { return c & ~CAPACITY; }
// 获取线程池当前运行的线程数量
private static int workerCountOf(int c) { return c & CAPACITY; }
// 通过线程池状态和运行的线程数量获取ctl
private static int ctlOf(int rs, int wc) { return rs | wc; }
例子
public class ThreadPoolTest {
private static void getThreadPoolState(ThreadPoolExecutor pool) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, NoSuchFieldException {
final int COUNT_BITS = Integer.SIZE - 3;
final int CAPACITY = (1 << COUNT_BITS) - 1;
// runState is stored in the high-order bits
final int RUNNING = -1 << COUNT_BITS;
final int SHUTDOWN = 0 << COUNT_BITS;
final int STOP = 1 << COUNT_BITS;
final int TIDYING = 2 << COUNT_BITS;
final int TERMINATED = 3 << COUNT_BITS;
Class<?> clazz = ThreadPoolExecutor.class;
// 使用反射获取 runState 字段
Field runStateField = ThreadPoolExecutor.class.getDeclaredField("ctl");
runStateField.setAccessible(true);
// 获取 runState 的值
AtomicInteger runState = (AtomicInteger) runStateField.get(pool);
// 获取方法名和参数类型
String methodName = "runStateOf";
Class<?>[] parameterTypes = {int.class};
// 获取方法对象
Method method = clazz.getDeclaredMethod(methodName, parameterTypes);
// 设置方法可访问性为 true
method.setAccessible(true);
// 设置方法的参数值
Object[] arguments = {runState.get()};
// 调用方法
Object result = method.invoke(pool, arguments);
if ((int) result == RUNNING) {
System.out.println("RUNNING");
} else if ((int) result == SHUTDOWN) {
System.out.println("SHUTDOWN");
}else if ((int) result == STOP) {
System.out.println("STOP");
}else if ((int) result == TIDYING) {
System.out.println("TIDYING");
}else if ((int) result == TERMINATED) {
System.out.println("TERMINATED");
}
}
}
class ThreadDemo implements Runnable {
@Override
public void run() {
try {
Thread.sleep(50000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName());
}
}
RUNNING
public static void main(String[] args) throws InterruptedException, NoSuchFieldException, InvocationTargetException, NoSuchMethodException, IllegalAccessException {
ThreadPoolExecutor pool = new ThreadPoolExecutor(1, 5, 1000, TimeUnit.MILLISECONDS, new SynchronousQueue<>(), Executors.defaultThreadFactory(), new ThreadPoolExecutor.DiscardOldestPolicy());
for (int i = 0; i < 3; i++) {
pool.submit(new ThreadDemo());
}
getThreadPoolState(pool);
}
// 输出
RUNNING
SHUTDOWN
public static void main(String[] args) throws InterruptedException, NoSuchFieldException, InvocationTargetException, NoSuchMethodException, IllegalAccessException {
ThreadPoolExecutor pool = new ThreadPoolExecutor(1, 5, 1000, TimeUnit.MILLISECONDS, new SynchronousQueue<>(), Executors.defaultThreadFactory(), new ThreadPoolExecutor.DiscardOldestPolicy());
for (int i = 0; i < 3; i++) {
pool.submit(new ThreadDemo());
}
getThreadPoolState(pool);
}
// 输出
SHUTDOWN
STOP
public static void main(String[] args) throws InterruptedException, NoSuchFieldException, InvocationTargetException, NoSuchMethodException, IllegalAccessException {
ThreadPoolExecutor pool = new ThreadPoolExecutor(1, 5, 1000, TimeUnit.MILLISECONDS, new SynchronousQueue<>(), Executors.defaultThreadFactory(), new ThreadPoolExecutor.DiscardOldestPolicy());
for (int i = 0; i < 3; i++) {
pool.submit(new ThreadDemo());
}
pool.shutdownNow();
getThreadPoolState(pool);
}
// 输出 大部分时候都会输出TERMINATED,偶尔运行慢或者调度慢了,可以出现STOP
STOP | TERMINATED
TIDYING由于中间没有其他状态,且切换到TERMINATED状态太快,就不举例了
创建线程池
/*
* @param corePoolSize 线程池中核心线程数
* @param maximumPoolSize 在高并发时,在线程阻塞队列已满的情况下,还可额外常见线程,包括核心线程的线程总数
* @param keepAliveTime 因阻塞队列满而创建的线程,在空闲keepAliveTime时间后,进行销毁
* @param unit keepAliveTime 单位
* @param workQueue 任务队列
* @param threadFactory 创建线程的factory
* @param handler 线程数量达到最大线程数量并且任务队列也是满的情况下,线程池的拒绝策略
*/
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;
}
此时线程池对象只是创建了一个普通的对象,还没有任何线程。
参数说明
maximumPoolSize
当核心线程数和队列都满了时,新提交的任务仍然可以通过创建新的工作线程(叫它非核心线程),直到工作线程数达到 maximumPoolSize 为止,这样就可以缓解一时的高峰期了,而用户也不用设置过大的核心线程数。
keepAliveTime
当高峰时期过去后,核心线程与非核心线程都一直空跑着,浪费资源。我们可以给非核心线程设定一个超时时间 keepAliveTime,当这么长时间没能从队列里获取任务时,就不再等了,销毁线程。
workQueue
阻塞队列可以阻塞,当阻塞队列当队列里面没有值时,会阻塞直到有值输入。输入也一样,当队列满的时候,会阻塞,直到队列有空间。
任务队列
getTask()有一个从任务队列获取任务的步骤,不同的任务队列有不同的任务存取策略,以下介绍一下可选的任务队列:
名称 | 描述 |
---|---|
ArrayBlockingQueue | 一个用数组实现的有界阻塞队列,此队列按照先进先出(FIFO)的原则对元素进行排序,并发采用可重入锁来控制 |
LinkedBlockingQueue | 一个用链表结构组成的有界队列,此队列按照先进先出(FIFO)的原则对元素进行排序 |
PriorityBlockingQueue | 一个支持线程优先级排序的无界队列 |
DelayQueue | 一个实现PriorityBlockingQueue实现延迟获取的无界队列,在创建元素时,可以指定多久才能从队列中获取当前元素 |
SynchronousQueue | 一个不存储元素的阻塞队列,每一个put操作必须等待take操作。支持公平锁和非公平锁。Executors.newCachedThreadPool()就使用了SynchronousQueue |
LinkedTransferQueue | 一个由链表结构组成的无界阻塞队列,相当于其它队列,LinkedTransferQueue队列多了transfer和tryTransfer方法 |
LinkedBlockingDeque | 一个由链表结构组成的双向阻塞队列 |
- 阻塞队列
- 阻塞队列的操作
阻塞队列包括了非阻塞队列中的大部分方法,上面列举的5个方法在阻塞队列中都存在,但是要注意这5个方法在阻塞队列中都进行了同步措施。
除此之外,阻塞队列提供了另外4个非常有用的方法:
put(E e):用来向队尾存入元素,如果队列满,则等待;
take():用来从队首取元素,如果队列为空,则等待;
offer(E e,long timeout, TimeUnit unit):用来向队尾存入元素,如果队列满,则等待一定的时间,当时间期限达到时,如果还没有插入成功,则返回false;否则返回true;
poll(long timeout, TimeUnit unit):用来从队首取元素。如果队列空,则会等待 timeout 时间后进行一次重试,如果取不到,则返回null;否则返回取得的元素;
Executors
默认的构造方法来创建线程池,参数过多,JDK提供了工厂方法,来创建线程池
handler
如果线程达到最大线程数,救急线程也满负荷,且有界队列也满了,JDK 提供了4种拒绝策略
-
AbortPolicy: 调用者抛出RejectedExecutionException, 默认策略
-
CallerRunsPolicy: 调用者运行任务
-
DiscardPolicy: 放弃本次任务
-
DiscardOldestPolicy: 放弃队列中最早的任务,本任务取而代之
submit
线程池使用流程图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LYqr4mp2-1689146849496)(https://img.itya.xyz/picgo/java%E7%BA%BF%E7%A8%8B%E6%B1%A0%E6%B5%81%E7%A8%8B202307111128746.png)]
线程池例子
package com.zyh.java;
import java.util.concurrent.*;
public class ThreadPoolTest {
public static void main(String[] args) throws InterruptedException {
ExecutorService pool = new ThreadPoolExecutor(1, 5, 1000, TimeUnit.MILLISECONDS, new SynchronousQueue<>(), Executors.defaultThreadFactory());
for (int i = 0; i < 10; i++) {
pool.submit(new ThreadDemo());
}
}
}
class ThreadDemo implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
// 输出
pool-1-thread-1
pool-1-thread-2
pool-1-thread-3
pool-1-thread-4
pool-1-thread-5
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@681a9515 rejected from java.util.concurrent.ThreadPoolExecutor@3af49f1c[Running, pool size = 5, active threads = 3, queued tasks = 0, completed tasks = 2]
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:112)
at com.zyh.java.ThreadPoolTest.main(ThreadPoolTest.java:9)
上述代码中,由于SynchronousQueue的容量为0且提交速度较快,当提交到第六个线线程时,线程池中的所有线程均未执行,在submit第二个线程是就会创建新的线程,当第六个线程提交时,此时,线程数已经达到最大线程数,且队列已满(容量为0);
下面看一下,从submit开始都发生了那些事情:
首先查看submit的源码
/**
* @throws RejectedExecutionException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
*/
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}
submit注释中写了两个异常,一个是如果任务无法被调度执行时抛出 RejectedExecutionException ,另一个是task为空,抛出空指针异常。
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
return new FutureTask<T>(runnable, value);
}
public FutureTask(Runnable runnable, V result) {
this.callable = Executors.callable(runnable, result);
this.state = NEW; // ensure visibility of callable
}
public static <T> Callable<T> callable(Runnable task, T result) {
if (task == null)
throw new NullPointerException();
return new RunnableAdapter<T>(task, result);
}
static final class RunnableAdapter<T> implements Callable<T> {
final Runnable task;
final T result;
RunnableAdapter(Runnable task, T result) {
this.task = task;
this.result = result;
}
public T call() {
task.run();
return result;
}
}
从上述源码中可知,newTaskFor创建了一个FutureTask对象,并且将其状态置NEW。
execute(ftask);
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
/*
* 1。如果运行的线程少于corePoolSize,请尝试
* 以给定的命令作为第一个线程启动一个新线程
* 任务。调用addWorker会自动检查runState和
* workerCount,这样可以防止误报警
* 在不应该执行线程时返回false。
*/
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
/*
* 2。如果一个任务可以成功排队,那么我们仍然需要
* 检查我们是否应该添加一个线程
* (因为自上次检查以来现有的已死亡)或其他
* 进入此方法后池关闭。所以我们
* 重新检查状态,必要时回滚队列
* stopped,或者在没有线程时启动一个新线程。
*
*/
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);
}
/*
* 3。如果我们不能排队任务,那么我们尝试添加一个新的
* 线程。如果它失败了,我们知道我们被关闭或饱和了
*,因此拒绝该任务。
*/
else if (!addWorker(command, false))
reject(command);
}
其中涉及到了几个方法workerCountOf()、addWorker()、isRunning()、remove()、reject()
其中workerCountOf()、isRunning()很简单只是返回线程数量和判断线程池的状态。
先看remove
remove
public boolean remove(Runnable task) {
boolean removed = workQueue.remove(task);
tryTerminate(); // In case SHUTDOWN and now empty
return removed;
}
addWorker
/*
根据当前工作线程池的状态和给定的边界(core或maximum)检查是否可以添加新的工作线程。如果可以,worker的计数会相应地调整,会创建并启动一个新的worker,将firstTask作为它的第一个任务。如果线程池已停止或关闭,此方法返回false。如果线程工厂请求创建线程失败,它也会返回false。如果线程创建失败,无论是由于线程工厂返回null,还是由于异常(通常是thread .start()中的OutOfMemoryError),我们都会干净地回滚。
形参:
firstTask – 当firsrTask不为空时且线程数量少于于corePoolSize时,做为线程的第一个任务,或者当队列已满时,作为第一个任务创建非核心线程。
core – 如果为true,则使用corePoolSize绑定,否则使用maximumPoolSize。(这里使用布尔指示符而不是值,以确保在检查其他池状态后读取新值)。.
返回值:
true if successful
*/
private boolean addWorker(Runnable firstTask, boolean core) {
// 做一个标记类似goto的效果
retry:
for (;;) {
int c = ctl.get();
// 运行状态
int rs = runStateOf(c);
// 先做一个到底应不应该创建线程的判断
// 这个判断条件可以简化为 (rs >= SHUTDOWN && (rs != SHUTDOWN || firstTask != null || // workQueue.isEmpty()))
// 分为三种情况:1. rs > SHUTDOWN (线程池状态处于STOP、TIDYING、TERMINATED,添加工作线程失败)
// 2.rs == SHUTDOWN && firstTask != null
// 3.rs == SHUTDOWN && workQueue.isEmpty()
// 在这三种情况下,都不会再创建新的线程
if (rs >= SHUTDOWN &&
! ( rs == SHUTDOWN && firstTask == null &&! workQueue.isEmpty() )
)
return false;
for (;;) {
// 线程数量数量超过最大值,无法新增新线程
int wc = workerCountOf(c);
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
// 新增线程数,如果成功,则跳出循环
if (compareAndIncrementWorkerCount(c))
break retry;
// 再次获取c
c = ctl.get(); // Re-read ctl
// 线程池的状态是否等于最开始的状态
if (runStateOf(c) != rs)
// 不等于表示线程池有改变,需要重新执行一遍之前的操作
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
}
// 新增线程
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
// 创建了一个worker对象
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
// ReentrantLock独占锁
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// 再次获取线程池状态
int rs = runStateOf(ctl.get());
// 先做一个是否可以运行线程的判断
// 1.线程池状态处于运行状态
// 2.线程池状态处于SHUTDOWN状态但task==null,因为SHUTDOWN状态不接受新的任务
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
// 将worker添加到一个HashSet
workers.add(w);
int s = workers.size();
// 记录出现的最大线程数量
if (s > largestPoolSize)
largestPoolSize = s;
// 线程添加成功
workerAdded = true;
}
} finally {
mainLock.unlock();
}
if (workerAdded) {
// 执行
t.start();
// 启动成功标志
workerStarted = true;
}
}
} finally {
// 启动失败标志,加入到启动失败
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
Worker类
Worker 是 ThreadPoolExecutor
的一个内部类,主要是用来维护线程执行任务的中断控制状态,它实现了Runnable 接口同时继承了AQS,实现 Runnable 接口意味着 Worker 就是一个线程,继承 AQS 是为了实现独占锁这个功能。
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;
/** Thread this worker is running in. Null if factory fails. */
// 执行任务的线程
final Thread thread;
/** Initial task to run. Possibly null. */
// 执行的任务
Runnable firstTask;
// 完成的任务数
volatile long completedTasks;
/**
* Creates with given first task and thread from ThreadFactory.
* @param firstTask the first task (null if none)
*/
Worker(Runnable firstTask) {
// 新建线程的时候,设置state -1 是为了防止线程还未执行时(线程只有在执行的时候才会被中断),就被 // 其它线程显式调用shutdown方法中断了,因为中断是要判断state大于等于0才会中断
setState(-1);
this.firstTask = firstTask;
// 新建了一个线程
this.thread = getThreadFactory().newThread(this);
}
/** Delegates main run loop to outer runWorker */
public void run() {
runWorker(this);
}
}
DefaultThreadFactory
Executors类中新建线程的方式有一个默认的实现
static class DefaultThreadFactory implements ThreadFactory {
// 系统中,可能不止一个线程池,所以这个是个静态字段
private static final AtomicInteger poolNumber = new AtomicInteger(1);
private final ThreadGroup group;
// 每个线程归属于特定的线程池,所以这个字段非静态
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
DefaultThreadFactory() {
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
// 线程名字前缀
namePrefix = "pool-" +
poolNumber.getAndIncrement() +
"-thread-";
}
public Thread newThread(Runnable r) {
Thread t = new Thread(group, r,
namePrefix + threadNumber.getAndIncrement(),
0);
// 守护线程改为用户线程
if (t.isDaemon())
// 对于线程池的线程来说,都是用户线程
t.setDaemon(false);
if (t.getPriority() != Thread.NORM_PRIORITY)
// 线程优先级都是一样的
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
}
runWorker、getTask
final void runWorker(Worker w) {
// 获取当前线程
Thread wt = Thread.currentThread();
// 获取任务
Runnable task = w.firstTask;
// 显式将任务置为空,防止产生错乱的问题
w.firstTask = null;
// 将线程state置为0(创建Worker的时候state为-1),运行线程时允许线程中断
w.unlock();
boolean completedAbruptly = true;
try {
// 循环判断任务(firstTask或从队列中获取的task)是否为空
while (task != null || (task = getTask()) != null) {
w.lock();
// 判断线程池的状态,是否处于stop状态,或者线程是否被中断
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;
// 线程执行完成个数,起到一个统计的作用
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
processWorkerExit(w, completedAbruptly);
}
}
// 从阻塞队列中获取任务
private Runnable getTask() {
boolean timedOut = false; // Did the last poll() time out?
for (;;) {
int c = ctl.get();
// 获取线程池状态
int rs = runStateOf(c);
// 1.线程池状态是STOP,TIDYING,TERMINATED
// 2.线程池shutdown并且队列是空的.
// 满足以上两个条件之一则工作线程数wc减去1,然后直接返回null
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
int wc = workerCountOf(c);
// allowCoreThreadTimeOut 是否允许核心工作线程超时销毁,默认是false,可以设置为true
// 工作线程数大于核心线程数
// 满足两个条件之一,timed为true
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
// 1.(工作线程数 > maximumPoolSize) || (timed == true && timedOut == true)
// 2.工作线程数 > 1或者队列为空
// 一般情况下,在工作线程数 > maximumPoolSize 并且任务队列为空的情况下会触发这个条件(因为队列不为空下面的超时拉取的返回值R肯定不为null,timeOut自然不会为true)
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
// 线程数 -1
if (compareAndDecrementWorkerCount(c))
return null;
continue;
}
try {
// 如果timed为true,通过poll()方法做超时拉取,keepAliveTime时间内没有等待到有效的任务,则返回null
// 如果timed为false,通过take()做阻塞拉取,会阻塞到有下一个有效的任务时候再返回(一般不会是null)
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;
// 取不到任务的时候timedOut = true
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
processWorkerExit
// completedAbruptly:true表示用户是异常退出
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 {
// 统计已完成的任务数
completedTaskCount += w.completedTasks;
// 将工作线程数移除
workers.remove(w);
} finally {
mainLock.unlock();
}
// 尝试中断空闲线程
tryTerminate();
int c = ctl.get();
// 如果当前线程池状态处于RUNNING、SHUTDOWN状态
if (runStateLessThan(c, STOP)) {
// 工作线程非异常
if (!completedAbruptly) {
// allowCoreThreadTimeOut这个值表示是否允许核心工作线程超时销毁
// 如果允许,那么核心工作线程数最小为0
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
// 如果最小保留的核心线程数为0并且任务队列不为空,表示至少还需要一个线程将任务完成
if (min == 0 && ! workQueue.isEmpty())
// 最小线程数改为1
min = 1;
if (workerCountOf(c) >= min)
return; // replacement not needed
}
// 如果当前运行的Worker数比当前需要的Worker数少的话,会调用addWorker,添加新的Worker
addWorker(null, false);
}
}
tryTerminate
final void tryTerminate() {
for (;;) {
int c = ctl.get();
// 1.运行状态
// 2.TIDYING或者TERMINATED状态
// 3.SHUTDOWN状态并且队列不为空
if (isRunning(c) ||
runStateAtLeast(c, TIDYING) ||
(runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()) )
return;
// 当前线程数量不为0
if (workerCountOf(c) != 0) { // Eligible to terminate
interruptIdleWorkers(ONLY_ONE);
return;
}
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// 将线程池状态设置为TIDYING,并且设置线程数量为0
if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
try {
terminated();
} finally {
// 设置线程池状态并设置线程数量
ctl.set(ctlOf(TERMINATED, 0));
// 唤醒所有等待线程池终止的线程
termination.signalAll();
}
return;
}
} finally {
mainLock.unlock();
}
// else retry on failed CAS
}
}
拒绝策略
拒绝策略 | 拒绝方式 |
---|---|
AbortPolicy | 直接抛出一个运行期异常 |
DiscardPolicy | 默默地丢弃掉提交的任务,什么都不做且不抛出任何异常 |
DiscardOldestPolicy | 丢弃掉阻塞队列中存放时间最久的任务(队头元素),并且为当前所提交的任务留出一个队列中的空闲空间,以便将其放进到队列中 |
CallerRunsPolicy | 直接由提交任务的线程来运行这个提交的任务 |
// 直接由提交任务的线程来运行这个提交的任务
public static class CallerRunsPolicy implements RejectedExecutionHandler {
/**
* Creates a {@code CallerRunsPolicy}.
*/
public CallerRunsPolicy() { }
/**
* Executes task r in the caller's thread, unless the executor
* has been shut down, in which case the task is discarded.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
r.run();
}
}
}
// 直接抛出异常
public static class AbortPolicy implements RejectedExecutionHandler {
/**
* Creates an {@code AbortPolicy}.
*/
public AbortPolicy() { }
/**
* Always throws RejectedExecutionException.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
* @throws RejectedExecutionException always
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException("Task " + r.toString() +
" rejected from " +
e.toString());
}
}
/**
* A handler for rejected tasks that silently discards the
* rejected task.
*/
// 默默地丢弃掉被拒绝的任务
public static class DiscardPolicy implements RejectedExecutionHandler {
/**
* Creates a {@code DiscardPolicy}.
*/
public DiscardPolicy() { }
/**
* Does nothing, which has the effect of discarding task r.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
*/
// 这个方法什么都不做
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
}
}
/**
* A handler for rejected tasks that discards the oldest unhandled
* request and then retries {@code execute}, unless the executor
* is shut down, in which case the task is discarded.
*/
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
/**
* Creates a {@code DiscardOldestPolicy} for the given executor.
*/
public DiscardOldestPolicy() { }
/**
* Obtains and ignores the next task that the executor
* would otherwise execute, if one is immediately available,
* and then retries execution of task r, unless the executor
* is shut down, in which case task r is instead discarded.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
*/
// 将队头元素删除掉,移除掉最老的任务
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
// 判断线程池是否已关闭
if (!e.isShutdown()) {
e.getQueue().poll();
e.execute(r);
}
}
}
CallerRunsPolicy
package com.zyh.java;
import java.util.concurrent.*;
public class ThreadPoolTest {
public static void main(String[] args) throws InterruptedException {
ExecutorService pool = new ThreadPoolExecutor(1, 5, 1000, TimeUnit.MILLISECONDS, new SynchronousQueue<>(), Executors.defaultThreadFactory(),new ThreadPoolExecutor.CallerRunsPolicy());
for (int i = 0; i < 6; i++) {
pool.submit(new ThreadDemo());
}
}
}
class ThreadDemo implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
// 输出 -----CallerRunsPolicy
main
pool-1-thread-1
pool-1-thread-3
pool-1-thread-2
pool-1-thread-4
pool-1-thread-5
// 输出 -----AbortPolicy
pool-1-thread-1
pool-1-thread-2
pool-1-thread-3
pool-1-thread-4
pool-1-thread-5
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@681a9515 rejected from java.util.concurrent.ThreadPoolExecutor@3af49f1c[Running, pool size = 5, active threads = 3, queued tasks = 0, completed tasks = 2]
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:112)
at com.zyh.java.ThreadPoolTest.main(ThreadPoolTest.java:9)
// 输出 -----DiscardPolicy
pool-1-thread-1
pool-1-thread-2
pool-1-thread-3
pool-1-thread-4
pool-1-thread-5
public static void main(String[] args) throws InterruptedException, NoSuchFieldException, InvocationTargetException, NoSuchMethodException, IllegalAccessException {
ThreadPoolExecutor pool = new ThreadPoolExecutor(1, 2, 1000, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(2), Executors.defaultThreadFactory(), new ThreadPoolExecutor.DiscardOldestPolicy());
for (int i = 0; i < 6; i++) {
pool.submit(new ThreadDemo(i));
}
}
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName() + " " + i);
}
// 输出 -----DiscardOldestPolicy
pool-1-thread-2 3
pool-1-thread-1 0
pool-1-thread-2 4
pool-1-thread-1 5