1. Why use thread pool
-
Reduce resource consumption. Reduce the consumption caused by thread creation and destruction by reusing created threads.
-
Improve responsiveness. When a task arrives, the task can be executed immediately without waiting for the thread to be created.
-
Improve thread manageability. Threads are scarce resources. If they are created without restrictions, they will not only consume system resources, but also reduce the stability of the system. Using thread pools can be used for unified allocation, tuning, and monitoring.
2. Detailed explanation of ThreadPoolExecutor thread pool class parameters
parameter | illustrate |
---|---|
corePoolSize | The number of core threads, the minimum number of thread pool maintenance threads |
maximumPoolSize | The maximum number of thread pool maintenance threads |
keepAliveTime | The longest idle time of other threads in the thread pool except core threads. Idle threads that exceed this time will be destroyed. |
unit | The unit of keepAliveTime, several static properties in TimeUnit: NANOSECONDS, MICROSECONDS, MILLISECONDS, SECONDS |
workQueue | The task buffer queue used by the thread pool |
threadFactory | Thread factory, used to create threads, generally use the default |
handler | Thread pool's processing strategy for rejected tasks |
When the thread pool task cannot be processed (when it is considered that it cannot be processed), it can be processed through the strategy specified by the handler. ThreadPoolExecutor provides four strategies:
- ThreadPoolExecutor.AbortPolicy: Aborts the task and throws a RejectedExecutionException exception; it is also the default processing method.
- ThreadPoolExecutor.DiscardPolicy: Discards tasks, but does not throw exceptions.
- ThreadPoolExecutor.DiscardOldestPolicy: Discard the task at the front of the queue and retry the task (repeat this process)
- ThreadPoolExecutor.CallerRunsPolicy: The task is handled by the calling thread
The processing method can be customized by implementing the RejectedExecutionHandler interface.
3. Thread pool task execution
1. Add an execution task
- submit() This method returns a Future object, which can execute the thread with the return value; or execute the thread that can be canceled at any time. The get() method of the Future object gets the return value. cancel(true/false) of the Future object cancels the task, and returns false if it has not started or completed. The parameter indicates whether to interrupt the executing thread.
- execute() has no return value.
2. Thread pool task submission process
2.1. If the number of threads in the thread pool is less than corePoolSize at this time, even if the threads in the thread pool are all idle, new threads should be created to process the added tasks.
2.2. If the number in the thread pool is equal to corePoolSize at this time, but the buffer queue workQueue is not full, then the task is put into the buffer queue.
2.3. If the number in the thread pool is greater than or equal to corePoolSize at this time, the buffer queue workQueue is full, and the number in the thread pool is less than the maximumPoolSize, create a new thread to process the added task.
2.4. If the number in the thread pool is greater than corePoolSize at this time, the buffer queue workQueue is full, and the number in the thread pool is equal to the maximumPoolSize, then the task is processed by the strategy specified by the handler.
2.5. When the number of threads in the thread pool is greater than corePoolSize, if a thread idle time exceeds keepAliveTime, the thread will be terminated. In this way, the thread pool can dynamically adjust the number of threads in the pool.
The summary is: the priority of processing task judgment is core thread corePoolSize, task queue workQueue, maximum thread maximumPoolSize, if all three are full, use handler to process rejected tasks.
Notice:
- When the workQueue uses an unbounded queue, the maximumPoolSize parameter becomes meaningless, such as new LinkedBlockingQueue(), or new ArrayBlockingQueue(Integer.MAX_VALUE);
- When using the SynchronousQueue queue, because the queue has no capacity, the task will not be queued. If there is no idle thread in the thread pool, a new thread will be created immediately to receive the task. The maximumPoolSize should be set larger.
- keepAliveTime has no effect when the number of core threads and maximum threads are equal.
3. The thread pool is closed
3.1. shutdown() does not accept new tasks, it will process added tasks 3.2. shutdownNow() does not accept new tasks, does not process added tasks, and interrupts the tasks being processed
4. Introduction to common queues
4.1. ArrayBlockingQueue: This is a fixed-capacity bounded blocking queue implemented by an array.
4.2. SynchronousQueue: No capacity, no data can be cached; each put must wait for a take; when offer(), if there is no other thread in poll() or take(), it returns false.
4.3. LinkedBlockingQueue: This is a default unbounded blocking queue implemented by a singly linked list. LinkedBlockingQueue provides an optional bounded constructor, and when no capacity is specified, the capacity defaults to Integer.MAX_VALUE.
Queue operations:
method | illustrate |
---|---|
add | Increment an index; if the queue is full, throw an exception |
remove | Removes and returns the element at the head of the queue; if the queue is empty, throws an exception |
offer | Adds an element and returns true; if the queue is full, returns false |
poll | Removes and returns the element at the head of the queue; returns null if the queue is empty |
put | add an element; block if queue is full |
take | Remove and return the element at the head of the queue; block if the queue is empty |
element | Returns the element at the head of the queue; if the queue is empty, throws an exception |
peek | Returns the element at the head of the queue; returns null if the queue is empty |
5. Executors thread factory class
1. Executors.newCachedThreadPool(); Description: Create a cacheable thread pool. If the length of the thread pool exceeds the processing needs, the idle threads can be flexibly recovered. If there is no recovery, a new thread will be created. Internal implementation: new ThreadPoolExecutor(0, Integer. MAX_VALUE,60L,TimeUnit.SECONDS,new SynchronousQueue<runnable>());</runnable>
2. Executors.newFixedThreadPool(int); Description: Create a fixed-length thread pool, which can control the maximum number of concurrent threads. Exceeded threads will wait in the queue. Internal implementation: new ThreadPoolExecutor(nThreads, nThreads,0L,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<runnable>());</runnable>
3. Executors.newSingleThreadExecutor(); Description: Create a single-threaded thread pool, which only uses a single worker thread to execute tasks to ensure that all tasks are executed in order. Internal implementation: new ThreadPoolExecutor(1,1,0L,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<runnable>())</runnable>
4. Executors.newScheduledThreadPool(int); Description: Create a fixed-length thread pool to support timing and periodic task execution. Internal implementation: new ScheduledThreadPoolExecutor(corePoolSize)
[Attachment] Specifications for the use of thread pools in the Alibaba Java Development Manual
- [Mandatory] When creating a thread or thread pool, please specify a meaningful thread name, which is convenient for backtracking when an error occurs. Positive example:
public class TimerTaskThread extends Thread {
public TimerTaskThread(){
super.setName("TimerTaskThread");
...
}
}
-
[Mandatory] Thread resources must be provided by the thread pool. Explicit creation of threads in the application is not allowed. Description: The advantage of using a thread pool is to reduce the time spent on creating and destroying threads and the overhead of system resources, and solve the problem of insufficient resources. If the thread pool is not used, it may cause the system to create a large number of threads of the same type, which may cause the problem of running out of memory or "excessive switching".
-
[Mandatory] Executors are not allowed to create thread pools, but ThreadPoolExecutors are used. This way of processing allows the writers to be more specific about the running rules of thread pools and avoid the risk of resource exhaustion.
Note: The disadvantages of the thread pool object returned by Executors are as follows: 1) FixedThreadPool and SingleThreadPool: The allowed request queue length is Integer.MAX_VALUE, which may accumulate a large number of requests, resulting in OOM. 2) CachedThreadPool and ScheduledThreadPool: The allowed number of threads to be created is Integer.MAX_VALUE, which may create a large number of threads, resulting in OOM.
6. Summary
ThreadPoolExecutor defines different types of thread pools through several core parameters, which are suitable for different usage scenarios; among them, when the task is submitted, it will judge corePoolSize, workQueque, and maximumPoolSize in turn, and different states will be processed differently. The water in the technical field is too deep. If it is not used daily, some knowledge points will be almost forgotten after a basic period of time. Therefore, it is necessary to review and summarize in stages to consolidate your technical foundation.