preface
What is a thread pool
- A thread usage pattern. Too many lines will bring scheduling overhead, which will affect cache locality and overall performance. A thread pool maintains multiple threads, waiting to be assigned tasks that can be executed concurrently. This avoids the cost of creating and destroying threads while working on short-duration tasks.
- Thread pools not only ensure full utilization of CPU cores, but also prevent overscheduling. The number of threads available should depend on the number of concurrent processors available, processor cores, memory, network sockets, and so on. For example, the number of threads is usually the number of cpus +2, because too many threads cause additional thread switching overhead.
- That is, the number of threads in the thread pool is not better.
The scope of the thread pool
- A large number of threads are required to complete the task, and the time to complete the task is relatively short. Thread pooling is appropriate for WEB servers to perform tasks such as WEB page requests. Because the individual tasks are small and the number of tasks is huge.
- But for long tasks, the benefits of thread pools are less obvious. Because a thread cannot be reused after it is created, a large number of tasks block and no thread can execute it.
- Applications that are performance-critical, such as requiring servers to respond quickly to customer requests.
- An application that accepts a large number of requests without causing a large number of threads on the server. A large number of sudden customer requests, without a thread pool, will generate a large number of threads. Although the maximum number of threads in most operating systems is theoretically not an issue, creating a large number of threads in a short period of time can cause memory to reach its limit and cause an “out of memory (OOM)” error.
Java thread pool
Thread pools originate from the Executor interface
- One branch of the Executor interface, as shown below:
Use of thread pools
Code sample
public class ExecutorTest2 {
public static void main(String[] args) {
ExecutorService executorService = new ThreadPoolExecutor(8.10.0, TimeUnit.SECONDS,
new LinkedBlockingDeque<>(5), new ThreadPoolExecutor.AbortPolicy());// Create a thread pool
Runnable runnable = ()-> {// The contents of the runable task
try {
//System.out.println(executorService);
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName());
} catch(Exception e) { e.printStackTrace(); }}; IntStream.range(0.9).forEach(i-> executorService.submit(runnable));// Submit 9 tasks like thread poolexecutorService.shutdown(); }}Copy the code
Creating a thread pool
The Executors class has factory methods that can be used to create thread pools, but they’re not used in real applications.
Constructor of ThreadPoolExecutor
Parameter interpretation
Parameters:
- CorePoolSize – Number of core threads to keep in the pool, even if they are idle, unless allowCoreThreadTimeOut is set
- MaximumPoolSize – The maximum number of threads allowed in the pool
- KeepAliveTime – When the number of threads is greater than the number of cores, this is the maximum time that extra idle threads can wait for a new task before terminating.
- Unit – keepAliveTime Time unit of the keepAliveTime parameter
- WorkQueue – A queue used to save tasks before they are executed. This queue will only hold Runnable tasks submitted by the execute method.
- ThreadFactory – The factory that the executable uses to create new threads
- Handler – The handler used when a task cannot be put into a thread pool because thread maximumPoolSize and workQueue capacity have been reached
Throws: IllegalArgumentException
- If one of the following is true:
- corePoolSize < 0
keepAliveTime < 0
maximumPoolSize <= 0
maximumPoolSize < corePoolSize
- corePoolSize < 0
NullPointerException
- If workQueue or threadFactory or Handler is null
Abstraction about thread pools and the flow of execution
- abstract
- process
General execution strategy for thread pools:
- If the number of threads executing in the thread pool is < corePoolSize, the thread pool will preferentially create new threads rather than add submitted tasks to the workQueue.
- If the number of threads executing in the thread pool >= corePoolSize, the thread pool will preferentially queue the submitted task over creating a new thread.
- If the submitted task cannot be added to the blocking queue, the thread pool creates a new thread. If the number of threads created exceeds maximumPoolSize, the rejection policy (handler) takes effect.
It’s time to read the JDK source code again
Rejection policies
- AbortPolicy
- DiscardPolicy
- DiscardOldestPolicy
- CallerRunsPolicy
The RejectedExecutionHandler interface is not used in JDK RejectedExecutionHandler
The submit method
- The mechanism of the submit
Summary of thread pool task submission:
-
There are two submission methods: Submit and execute.
-
Submit comes in three ways, each of which ultimately converts the passed task into a Callable object for processing.
-
After a Callable object is constructed, the Execute method declared in the Executor interface is called for unified processing.
Status of the thread pool
There are five states in a thread pool:
- RUNNING: The thread pool can receive new task submissions and can normally process tasks in the blocking queue.
- SHUTDOWN: No new task submissions are received, but the thread pool can continue to process tasks in the blocking queue.
- STOP: stops receiving new tasks and discards existing tasks in the blocking queue. In addition, it interrupts the task in progress.
- TIDYING: After all tasks are executed (including tasks in the blocking queue) and the number of active threads in the current thread pool drops to zero, the terminated method is called.
- TERMINATED: the TERMINATED state of the thread pool that will be under TERMINATED when the TERMINATED method is executed.
The thread pool state does not change continuously, it transitions to the appropriate state as the case may be. It doesn’t have to be RUNNING to SHUTDOWN. RUNNING -> SHUPDOWN: when the shutdown method of the thread pool is called, or when the Finalize method is implicitly called (the shutdown method is called internally). RUNNING, SHUTDOWN -> STOP: When the shutdownNow method of the thread pool is called. SHUTDOWN ->TIDYING: When both the thread pool and the blocking queue become empty. STOP ->TIDYING: When the thread pool becomes empty. TIDYING ->TERMINATED: when the TERMINATED method is TERMINATED.
State from JDK source
You can read the JDK to learn how to implement the execute method
How is thread pool state shutdown