search
HomeJavajavaTutorialJava thread pool framework core code analysis

In multi-threaded programming, it is unrealistic to allocate a thread to each task. The overhead and resource consumption of thread creation are very high. The thread pool emerged as the times require and has become a powerful tool for us to manage threads. Java provides a standard method to decouple the task submission process and execution process through the Executor interface, and uses Runnable to represent the task.

Now, let’s analyze ThreadPoolExecutor, the implementation of the Java thread pool framework.

The following analysis is based on JDK1.7

Life cycle

In ThreadPoolExecutor, the high 3 bits of CAPACITY are used to represent the running status, which are:

RUNNING: Receive new tasks and process tasks in the task queue
SHUTDOWN: Do not receive new tasks, but process tasks in the task queue
STOP: Do not receive new tasks, do not come out of the task queue, and interrupt all ongoing tasks
TIDYING: All tasks have been terminated, the number of worker threads is 0, reaching this state will Execute terminated()
TERMINATED: terminated() execution is completed

Java thread pool framework core code analysis

ThreadPoolExecutor uses atomic classes to represent status bits

private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));

Thread pool model

Core parameters

corePoolSize: the minimum number of surviving worker threads (if allowCoreThreadTimeOut is set , then the value is 0)
maximumPoolSize: the maximum number of threads, limited by CAPACITY
keepAliveTime: the survival time of the corresponding thread, the time unit is specified by TimeUnit
workQueue: work queue, storing tasks to be executed
RejectExecutionHandler: rejection policy, When the thread pool is full, it will trigger
Maximum capacity of the thread pool: The first three digits in CAPACITY are used as flag bits, which means that the maximum capacity of the worker thread is (2^29)-1

Four models

CachedThreadPool: one Cacheable thread pool. If the current size of the thread pool exceeds the processing demand, idle threads will be recycled. When demand increases, new threads can be added. There is no limit to the size of the thread pool.
FixedThreadPool: A fixed-size thread pool. When a task is submitted, a thread is created until the maximum number of thread pools is reached, at which time the size of the thread pool will no longer change.
SingleThreadPool: A single-threaded thread pool. It has only one worker thread to execute tasks. It can ensure that tasks are executed serially in the order in the queue. If this thread ends abnormally, a new thread will be created to execute the task.
ScheduledThreadPool: A fixed-size thread pool that performs tasks in a delayed or scheduled manner, similar to Timer.
Execute task execute

Core logic:

The current number of threads The current number of threads >= corePoolSize, and the task is added to the work queue successfully
Check the thread Whether the current status of the pool is RUNNING
If not, reject the task
If yes, determine whether the current number of threads is 0, if it is 0, add a worker thread.
Enable the ordinary thread execution task addWorker(command, false), and reject the task if it fails to start.
From the above analysis, we can summarize the four stages of thread pool operation:

poolSize poolSize == corePoolSize. At this time, the submitted task enters the work queue, and the worker thread obtains the task execution from the queue. At this time, the queue is not empty and not full.
poolSize == corePoolSize, and the queue is full, a new thread will be created to process the submitted tasks, but poolSize poolSize == maxPoolSize, and the queue is full, the rejection policy will be triggered at this time
Rejection policy

Earlier we mentioned that tasks that cannot be executed will be rejected. RejectedExecutionHandler is the interface for handling rejected tasks. Here are four rejection strategies.

AbortPolicy: Default policy, terminates the task, throws RejectedException
CallerRunsPolicy: Execute the current task in the caller thread, no exception is thrown
DiscardPolicy: Discard policy, directly discard the task, no exception is thrown
DiscardOldersPolicy: Discard the oldest task, execute The current task does not throw exceptions

Worker in the thread pool

Worker inherits AbstractQueuedSynchronizer and Runnable. The former provides the lock function to the Worker, and the latter executes the main method of the worker thread runWorker(Worker w) (gets the task execution from the task queue ). The Worker reference is stored in the workers collection and is guarded by mainLock.

private final ReentrantLock mainLock = new ReentrantLock();
private final HashSet<Worker> workers = new HashSet<Worker>();

Core function runWorker

The following is the simplified logic. Note: The run of each worker thread executes the following function

final void runWorker(Worker w) {
    Thread wt = Thread.currentThread();
    Runnable task = w.firstTask;
    w.firstTask = null;    while (task != null || (task = getTask()) != null) {
        w.lock();
        beforeExecute(wt, task);        
        task.run();
        afterExecute(task, thrown);
        w.unlock();
    }
    processWorkerExit(w, completedAbruptly);
}

从getTask()中获取任务 
锁住 worker 
执行beforeExecute(wt, task),这是ThreadPoolExecutor提供给子类的扩展方法 
运行任务,如果该worker有配置了首次任务,则先执行首次任务且只执行一次。 
执行afterExecute(task, thrown); 
解锁 worker 
如果获取到的任务为 null,关闭 worker 
获取任务 getTask

线程池内部的任务队列是一个阻塞队列,具体实现在构造时传入。

private final BlockingQueue<Runnable> workQueue;

getTask()从任务队列中获取任务,支持阻塞和超时等待任务,四种情况会导致返回null,让worker关闭。

现有的线程数量超过最大线程数量 
线程池处于STOP状态 
线程池处于SHUTDOWN状态且工作队列为空 
线程等待任务超时,且线程数量超过保留线程数量 
核心逻辑:根据timed在阻塞队列上超时等待或者阻塞等待任务,等待任务超时会导致工作线程被关闭。

timed = allowCoreThreadTimeOut || wc > corePoolSize;Runnable r = timed ?
    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
    workQueue.take();

在以下两种情况下等待任务会超时:

允许核心线程等待超时,即allowCoreThreadTimeOut(true) 
当前线程是普通线程,此时wc > corePoolSize 
工作队列使用的是BlockingQueue,这里就不展开了,后面再写一篇详细的分析。

总结

ThreadPoolExecutor基于生产者-消费者模式,提交任务的操作相当于生产者,执行任务的线程相当于消费者。 
Executors提供了四种基于ThreadPoolExecutor构造线程池模型的方法,除此之外,我们还可以直接继承ThreadPoolExecutor,重写beforeExecute和afterExecute方法来定制线程池任务执行过程。 
使用有界队列还是无界队列需要根据具体情况考虑,工作队列的大小和线程的数量也是需要好好考虑的。 
拒绝策略推荐使用CallerRunsPolicy,该策略不会抛弃任务,也不会抛出异常,而是将任务回退到调用者线程中执行。


Statement
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
How does IntelliJ IDEA identify the port number of a Spring Boot project without outputting a log?How does IntelliJ IDEA identify the port number of a Spring Boot project without outputting a log?Apr 19, 2025 pm 11:45 PM

Start Spring using IntelliJIDEAUltimate version...

How to elegantly obtain entity class variable names to build database query conditions?How to elegantly obtain entity class variable names to build database query conditions?Apr 19, 2025 pm 11:42 PM

When using MyBatis-Plus or other ORM frameworks for database operations, it is often necessary to construct query conditions based on the attribute name of the entity class. If you manually every time...

How to use the Redis cache solution to efficiently realize the requirements of product ranking list?How to use the Redis cache solution to efficiently realize the requirements of product ranking list?Apr 19, 2025 pm 11:36 PM

How does the Redis caching solution realize the requirements of product ranking list? During the development process, we often need to deal with the requirements of rankings, such as displaying a...

How to safely convert Java objects to arrays?How to safely convert Java objects to arrays?Apr 19, 2025 pm 11:33 PM

Conversion of Java Objects and Arrays: In-depth discussion of the risks and correct methods of cast type conversion Many Java beginners will encounter the conversion of an object into an array...

How do I convert names to numbers to implement sorting and maintain consistency in groups?How do I convert names to numbers to implement sorting and maintain consistency in groups?Apr 19, 2025 pm 11:30 PM

Solutions to convert names to numbers to implement sorting In many application scenarios, users may need to sort in groups, especially in one...

E-commerce platform SKU and SPU database design: How to take into account both user-defined attributes and attributeless products?E-commerce platform SKU and SPU database design: How to take into account both user-defined attributes and attributeless products?Apr 19, 2025 pm 11:27 PM

Detailed explanation of the design of SKU and SPU tables on e-commerce platforms This article will discuss the database design issues of SKU and SPU in e-commerce platforms, especially how to deal with user-defined sales...

How to set the default run configuration list of SpringBoot projects in Idea for team members to share?How to set the default run configuration list of SpringBoot projects in Idea for team members to share?Apr 19, 2025 pm 11:24 PM

How to set the SpringBoot project default run configuration list in Idea using IntelliJ...

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Atom editor mac version download

Atom editor mac version download

The most popular open source editor

SublimeText3 Linux new version

SublimeText3 Linux new version

SublimeText3 Linux latest version

mPDF

mPDF

mPDF is a PHP library that can generate PDF files from UTF-8 encoded HTML. The original author, Ian Back, wrote mPDF to output PDF files "on the fly" from his website and handle different languages. It is slower than original scripts like HTML2FPDF and produces larger files when using Unicode fonts, but supports CSS styles etc. and has a lot of enhancements. Supports almost all languages, including RTL (Arabic and Hebrew) and CJK (Chinese, Japanese and Korean). Supports nested block-level elements (such as P, DIV),

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

SecLists

SecLists

SecLists is the ultimate security tester's companion. It is a collection of various types of lists that are frequently used during security assessments, all in one place. SecLists helps make security testing more efficient and productive by conveniently providing all the lists a security tester might need. List types include usernames, passwords, URLs, fuzzing payloads, sensitive data patterns, web shells, and more. The tester can simply pull this repository onto a new test machine and he will have access to every type of list he needs.