**
This article was originally published in the wechat public number [Craig Wuji], pay attention to get more original quality content
**
preface
Yesterday, a student in the group asked about thread pools in Concurrent programming in Java. This article will introduce you to the topic that is often asked in interviews.
You will have a clearer idea of how thread pools work. This article will be from the following aspects to tell about the relevant knowledge, I believe you must have the patience to see after harvest, code word is not easy, don’t forget to “see”, “forward” oh.
- Why use thread pools
- How thread pools work
- The seven core parameters of the thread pool
- How do I use thread pools properly
The body of the
**
01 Why use thread pools
Before introducing a technology, the first question to answer is what problem the technology solves.
In the Java language, creating a thread seems simple enough. Implement the Runnable interface, and then simply create a new Thread as if it were an object.
But actually creating and destroying threads is much more than creating an object. Creating a thread requires calling the OPERATING system kernel’s API, and the operating system allocates a set of resources to it, so the overall cost is high, resulting in a thread being a heavyweight object that should be avoided with frequent creation and destruction.
Let’s talk about context switching for threads.
A CPU can only run one thread at a time. When it runs one thread, the CPU switches to another thread due to running out of time chips or blocking. This is called thread context switching.
In addition, the task of the current thread may not be completed, so the running state of the thread needs to be saved during the switchover, so that it can continue to run in the previous state when the next switchover comes back. This process involves the switch between user state and kernel state.
What are user mode and kernel mode?
When executing the user’s own code, it is said to be in user mode (user mode). At this time, the processor has the lowest privilege level, which is the privilege level of ordinary user processes. Most programs directly faced by users are running in user mode.
The processor is at its most privileged when it is in kernel run state (kernel state) when it is trapped in kernel code because of a system call. To perform operations such as file operations and network data sending, you must use system calls such as write and Send. These system calls call the kernel code. The kernel address space is switched from user mode to kernel mode to execute kernel code to complete the operation, and then switched back to user mode.
If there are a large number of concurrent threads, and each thread executes a short task and then terminates, creating threads frequently can greatly reduce the efficiency of the system because of the time it takes to create and destroy threads frequently.
To avoid excessive resource consumption, one of the best ways to reuse a thread is to let it continue to perform other tasks without destroying it after it completes one task.
Thread pooling is a thread usage pattern that brings a number of benefits:
(1) Avoid the cost of resource consumption caused by the repeated creation and overhead of threads.
(2) The task response speed is improved. When the task arrives, a thread is directly selected for execution without waiting for the creation of the thread.
(3) Improve the manageability of threads, thread unified allocation and management, but also convenient for unified monitoring and tuning.
This is the core design idea of thread pool, reuse threads, and amortize the cost of thread creation and destruction.
02 How thread pools work
The working principle of a thread pool can be simplified into the following steps:
(1) Inside the thread pool, a blocking queue (workQueue) and a group of worker threads are maintained. The number of worker threads can be specified when the thread pool is initialized.
(2) Users can submit tasks that need to be completed to the thread pool and the tasks will be added to the workQueue.
(3) The worker threads maintained in the thread pool consume and execute the tasks in the workQueue in sequence, and do not destroy the tasks after execution.
The 7 core parameters of the thread pool
You can create a thread pool using ThreadPoolExecutor by specifying seven core parameters, each of which represents the specific working behavior of the thread pool.
CorePoolSize (number of core threads)
The thread pool is analogous to a construction team, and threads are the workers of the construction team. Sometimes it is idle and there are few projects, but the construction team cannot demobilize all the workers and need to leave some core backbone for emergencies, so at least corePoolSize should be retained to stand firm.
CorePoolSize represents the number of core threads held in the thread pool. Core threads are kept alive, even if they are idle and have no work to execute, they are not destroyed.
MaximumPoolSize (maximum number of threads)
When a project is large, the construction team needs to add workers, but it can not be unlimited. Is added to the maximumPoolSize most people, when spare time, construction group will be laid off workers, but at least keep corePoolSize individuals.
KeepAliveTime&unit (keepAliveTime&unit)
As mentioned above, construction teams add and subtract workers according to the number of busy and idle projects. How do you define busy and idle in the programming world?
When the number of threads in the thread pool is greater than corePoolSize, a thread is idle if it does not perform any tasks for a period of time.
KeepAliveTime and Unit are the parameters that define this “period of time”. That is, if a thread has been idle for so long with keepAliveTime & Unit, the idle thread will be reclaimed.
workQueue
After a new task is submitted, it is first entered into the work queue, and then removed from the queue during task scheduling.
ThreadFactory (threadFactory)
A factory used when creating a new thread that allows you to customize how the thread is created, for example by giving the thread a meaningful name.
Handler (Rejection policy)
If all the threads in the thread pool are busy and the work queue is full (if the work queue is bounded), the thread pool will reject the submitted task.
The rejection policy can be specified with the handler parameter:
-
CallerRunsPolicy: The thread submitting the task executes the task itself.
-
AbortPolicy: default refusal strategies, discarding the task directly, throw RejectedExecutionException.
-
DiscardPolicy: Directly discards the task without any exception being thrown.
-
DiscardOldestPolicy: Discards the oldest task. DiscardOldestPolicy discards the earliest task and adds the new task to the work queue.
04 How to use a thread pool correctly
The default reject policy should be used with caution. You are advised to customize your own rejection policy if the task that the thread pool processes is very important. In practice, the custom rejection strategy is often used together with the demotion strategy.
With thread pools, you need to be aware of exception handling. A runtime exception occurs during the execution of a task, causing the thread executing the task to terminate. The safest and simplest solution is to catch all exceptions and handle them as needed.
Note that alibaba Java Development Manual also emphasizes that do not use Executors to directly create a thread pool. Use ThreadPoolExecutor to clear the running rules of the thread pool and avoid the risk of resource depletion.
* If the request queue length of FixedThreadPool and SingleThreadPool is Integer.MAX_VALUE, a large number of requests may accumulate and result in OOM.
(2) CachedThreadPool and ScheduledThreadPool allow the number of threads to be created as Integer.MAX_VALUE.
Original is not easy, thanks to the likes and forwarding of enthusiastic partners ~