Abstract: For the core class ThreadPoolExecutor of the thread pool, what are the important attributes and internal classes that provide important guarantees for the correct operation of the thread pool?
This article is shared from the HUAWEI cloud community " [High Concurrency] In-depth analysis of how the ThreadPoolExecutor class ensures the correct operation of the thread pool through the source code", author: Glacier.
For the core class ThreadPoolExecutor of the thread pool, what are the important attributes and internal classes that provide important guarantees for the correct operation of the thread pool? Today we will discuss these issues in depth together! !
Important attributes in the ThreadPoolExecutor class
In the ThreadPoolExecutor class, there are several very important properties and methods. Next, we will introduce these important properties and methods.
ctl related attributes
The constant ctl of the AtomicInteger type is an important attribute throughout the life cycle of the thread pool. It is an atomic object, mainly used to save the number of threads and the state of the thread pool. Let's look at the code related to this attribute as shown below.
//主要用来保存线程数量和线程池的状态,高3位保存线程状态,低29位保存线程数量
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
//线程池中线程的数量的位数(32-3)
private static final int COUNT_BITS = Integer.SIZE - 3;
//表示线程池中的最大线程数量
//将数字1的二进制值向右移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;
//获取线程状态
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; }
private static boolean runStateLessThan(int c, int s) {
return c < s;
}
private static boolean runStateAtLeast(int c, int s) {
return c >= s;
}
private static boolean isRunning(int c) {
return c < SHUTDOWN;
}
private boolean compareAndIncrementWorkerCount(int expect) {
return ctl.compareAndSet(expect, expect + 1);
}
private boolean compareAndDecrementWorkerCount(int expect) {
return ctl.compareAndSet(expect, expect - 1);
}
private void decrementWorkerCount() {
do {} while (! compareAndDecrementWorkerCount(ctl.get()));
}
The description of each state of the thread pool is as follows.
• RUNNING: running status, can receive newly submitted tasks, and can also process tasks in the blocking queue
• SHUTDOWN: Closed state, can no longer receive newly submitted tasks, but can process tasks that have been saved in the blocking queue. When the thread pool is in the RUNNING state, calling the shutdown() method will make the thread pool enter this state
• STOP: Cannot receive new tasks, and can not process tasks that have been saved in the blocking queue. It will interrupt the thread that is processing the task. If the thread pool is in the RUNNING or SHUTDOWN state, calling the shutdownNow() method will make the thread pool enter this state
• TIDYING: If all tasks have been terminated and the number of effective threads is 0 (the blocking queue is empty and the number of worker threads in the thread pool is 0), the thread pool will enter this state.
• TERMINATED: The thread pool in the TIDYING state calls the terminated () method, and the thread pool is used to enter the state
According to the ThreadPoolExecutor class, the conversion between the states of the thread pool can also be summarized as shown in the following figure.
• RUNNING -> SHUTDOWN: The shutdown() method is explicitly called, or the finalize() method is implicitly called
• (RUNNING or SHUTDOWN) -> STOP: call the shutdownNow() method explicitly
• SHUTDOWN -> TIDYING: When the thread pool and task queue are both empty
• STOP -> TIDYING: When the thread pool is empty
• TIDYING -> TERMINATED: When the terminated() hook method is executed
Other important attributes
In addition to ctl-related attributes, some other important attributes in the ThreadPoolExecutor class are as follows.
//用于存放任务的阻塞队列
private final BlockingQueue<Runnable> workQueue;
//可重入锁
private final ReentrantLock mainLock = new ReentrantLock();
//存放线程池中线程的集合,访问这个集合时,必须获得mainLock锁
private final HashSet<Worker> workers = new HashSet<Worker>();
//在锁内部阻塞等待条件完成
private final Condition termination = mainLock.newCondition();
//线程工厂,以此来创建新线程
private volatile ThreadFactory threadFactory;
//拒绝策略
private volatile RejectedExecutionHandler handler;
//默认的拒绝策略
private static final RejectedExecutionHandler defaultHandler = new AbortPolicy();
Important inner classes in the ThreadPoolExecutor class
In the ThreadPoolExecutor class, there are internal classes that are vital to the execution of the thread pool, the Worker internal class and the rejection strategy internal class. Next, we look at these internal classes respectively.
Worker inner class
From the point of view of the source code, the Worker class implements the Runnable interface, indicating that it is essentially a thread used to perform tasks. Next, we look at the source code of the Worker class, as shown below.
private final class Worker extends AbstractQueuedSynchronizer implements Runnable{
private static final long serialVersionUID = 6138294804551838833L;
//真正执行任务的线程
final Thread thread;
//第一个Runnable任务,如果在创建线程时指定了需要执行的第一个任务
//则第一个任务会存放在此变量中,此变量也可以为null
//如果为null,则线程启动后,通过getTask方法到BlockingQueue队列中获取任务
Runnable firstTask;
//用于存放此线程完全的任务数,注意:使用了volatile关键字
volatile long completedTasks;
//Worker类唯一的构造放大,传递的firstTask可以为null
Worker(Runnable firstTask) {
//防止在调用runWorker之前被中断
setState(-1);
this.firstTask = firstTask;
//使用ThreadFactory 来创建一个新的执行任务的线程
this.thread = getThreadFactory().newThread(this);
}
//调用外部ThreadPoolExecutor类的runWorker方法执行任务
public void run() {
runWorker(this);
}
//是否获取到锁
//state=0表示锁未被获取
//state=1表示锁被获取
protected boolean isHeldExclusively() {
return getState() != 0;
}
protected boolean tryAcquire(int unused) {
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
protected boolean tryRelease(int unused) {
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) {
}
}
}
}
In the construction method of the Worker class, it can be seen that the synchronization state state is first set to -1, which is set to -1 to prevent the runWorker method from being interrupted before it runs. This is because if other threads call the shutdownNow() method of the thread pool, if the value of the state state in the Worker class is greater than 0, the thread will be interrupted, and if the value of the state state is -1, the thread will not be interrupted.
The Worker class implements the Runnable interface and needs to rewrite the run method. The Worker's run method essentially calls the runWorker method of the ThreadPoolExecutor class. In the runWorker method, the unlock method is called first, which sets the state to 0, so Calling the shutDownNow method at this time will interrupt the current thread, and this time has entered the runWork method, it will not interrupt the thread before the runWorker method is executed.
Note: Everyone needs to focus on understanding the implementation of the Worker class.
Reject policy inner class
In the thread pool, if the workQueue blocking queue is full and there is no free thread pool, at this time, to continue to submit the task, a strategy needs to be adopted to handle the task. The thread pool provides a total of four strategies, as shown below.
• Throw an exception directly, which is also the default strategy. The implementation class is AbortPolicy.
• Use the thread of the caller to execute the task. The implementation class is CallerRunsPolicy.
• Discard the top task in the queue and execute the current task. The implementation class is DiscardOldestPolicy.
• Discard the current task directly. The implementation class is DiscardPolicy.
Four internal classes are provided in the ThreadPoolExecutor class to implement the corresponding strategy by default, as shown below.
public static class CallerRunsPolicy implements RejectedExecutionHandler {
public CallerRunsPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
r.run();
}
}
}
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);
}
}
}
We can also customize the rejection strategy by implementing the RejectedExecutionHandler interface and rewriting the rejectedExecution method of the RejectedExecutionHandler interface. When creating the thread pool, we call the ThreadPoolExecutor's construction method and pass in our own rejection strategy.
For example, the customized rejection policy is shown below.
public class CustomPolicy implements RejectedExecutionHandler {
public CustomPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
System.out.println("使用调用者所在的线程来执行任务")
r.run();
}
}
}
Use a custom rejection strategy to create a thread pool.
new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
Executors.defaultThreadFactory(),
Click to follow and learn about Huawei Cloud's fresh technology for the first time~
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。