Why use a thread pool?
A thread is an operating system concept. The operating system is responsible for creating, suspending, running, blocking, and terminating operations on this thread. While the operating system creates threads, switches thread states, and ends up with CPU scheduling-This is a time-consuming and system-intensive thing.
On the other hand, this is true in most real-world scenarios: the time to process a request is very short, but the number of requests is huge. In this technical context, if we create a single thread for each request, then all the resources of the physical machine are basically consumed by operating system creation threads, switching thread states, destroying threads, and the resources used for business request processing are reduced. So the best way to do this is to control the number of threads that are processing the request in one scope, ensuring that subsequent requests do not wait too long, and that the physical machine will use enough resources for the request processing itself.
In addition, some operating systems are limited by the maximum number of threads. When the number of threads running approximates this value, the operating system becomes unstable. This is why we want to limit the number of threads.
Basic usage of thread pool
The Java language provides us with the choice of two basic thread pools: Scheduledthreadpoolexecutor and Threadpoolexecutor. They all implement the Executorservice interface (note that the Executorservice interface itself is not directly related to the "thread pool", its definition is closer to the "executor", and "implementation using Thread management" is just one way of implementing it). In this article, we mainly focus on the Threadpoolexecutor class.
How to use the Threadpoolexecutor class:
Public class poolthreadsimple { Public Static void Main(string[] args)throwsThrowable {/* * Corepoolsize: Core size, when the thread pool is initialized, there will be such a large * maximumpoolsize: Max threads for thread pools * KeepAliveTime: If the current thread pool threads Greater than corepoolsize. * Extra thread, after waiting for keepalivetime time if no new thread task has been assigned to it, it will be recycled * unit: Wait Time keepalivetime units * * Work Queue: Waits for queues. The setting for this object is what this article will focus on * * /Threadpoolexecutor Poolexecutor =NewThreadpoolexecutor (5,Ten,1, Timeunit.minutes,NewSynchronousqueue<runnable> ()); for(intindex =0; Index <Ten; Index + +) {Poolexecutor.submit (NewPoolthreadsimple.testrunnable (index)); } }/** * This is the test thread * / Private Static class testrunnable implements Runnable { /** * Log * * Private StaticLog LOGGER = Logfactory.getlog (Testrunnable.class);/** * Record the unique number of the task so that it is well identified in the log */ PrivateInteger index; Public testrunnable(intIndex) { This. index = index; }/** * @return the index * * PublicIntegerGetIndex() {returnIndex }@Override Public void Run() {/* * thread, just do one thing: * Wait 60 seconds for the event to simulate the business operation process * */Thread CurrentThread = Thread.CurrentThread (); TestRunnable.LOGGER.info ("Thread:"+ Currentthread.getid () +"in the Task ("+ This. GetIndex () +") Start execution = = =");synchronized(CurrentThread) {Try{currentthread.wait (60000); }Catch(Interruptedexception e) {TestRunnable.LOGGER.error (E.getmessage (), E); }} TestRunnable.LOGGER.info ("Thread:"+ Currentthread.getid () +"in the Task ("+ This. GetIndex () +") Execution completed"); } }}
Below, the corepoolsize, Maximumpoolsize, KeepAliveTime, Timeunit, WorkQueue, threadfactory, handler parameters and some common/ The infrequently used settings are explained individually.
Threadpoolexecutor logical structure and mode of operation
In the above code, we used the simplest constructor in Threadpoolexecutor when we created the thread pool:
publicThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue)
Parameters that need to be passed into the constructor include Corepoolsize, Maximumpoolsize, KeepAliveTime, Timeunit, and Workqueue. to clearly understand the meaning of these parameters (and the parameters that will be introduced later), it is first to clarify the logical structure of the threadpoolexecutor thread pool.
It is important to note the concept that the container that exists in the thread pool must be a thread object, not the task you require to run (so call the thread pool instead of the task pool or the object pool); The task you require to run will be run by the thread pool assigned to a free thread.
From there, we can see several important elements that make up the thread pool:
wait Queue : As the name implies, you call the Submit () method of the thread pool object or the Execute () method, which requires the tasks that the thread pool runs (these tasks must implement the Runnable interface or the callable interface). But for some reason the thread pool does not run these tasks immediately, but instead feeds into a queue for execution.
Core thread : The thread pool is primarily used to perform tasks that are "core threads", and the number of "core threads" is determined by the Corepoolsize parameter that you set when you created the thread. If no special setting is made, the number of threads in the thread pool will always remain corepoolsize (excluding the creation phase).
non-core thread : Once the number of tasks is too large (determined by the nature of the wait queue), the thread pool creates a "non-core thread" temporary help run task. The part you set that is larger than the Corepoolsize parameter is less than the maximumpoolsize parameter, which is the maximum number of "non-core threads" that the thread pool can temporarily create. In this case, if a thread is not running any tasks, after waiting for keepalivetime time, the thread will be destroyed until the thread pool's number of threads has reached corepoolsize again.
The maximumpoolsize parameter is also the maximum number of threads allowed to be created by the current thread pool. The thread pool will not reclaim idle threads under any circumstances if the set corepoolsize parameter is the same as the set maximumpoolsize parameter. KeepAliveTime and Timeunit also lost their meaning.
The keepalivetime parameter and the timeunit parameter are also used together. The KeepAliveTime parameter indicates the quantization value of the wait time, Timeunit indicates the unit of quantization value. For example, Keepalivetime=1,timeunit is timeunit.minutes and the recycle threshold value for idle threads is 1 minutes.
Having said the logical structure of the thread pool, let's talk about how the thread pool handles one of the running tasks.
1.A thread pool can be required to perform a task first, either through the Submit () method provided by the thread pool or by the Execute () method. After the thread pool receives this request to perform the task, there are several processing situations:
1.1.If the number of threads running in the current thread pool has not reached the corepoolsize size, the line pool creates a new thread to run your task, regardless of whether the previously created thread is idle.
1.2.If the number of threads running in the current thread pool has reached the corepoolsize size set, the thread pool will add your task to the wait queue. Until one of the threads is idle, the thread pool takes a new task execution from the queue, based on the waiting queue rules set.
1.3.This task cannot join the wait queue if it is based on a queue rule. The thread pool will then create a "non-core thread" to run this task directly. Note that if the task executes successfully in this case, then the number of threads in the front-thread pool must be greater than corepoolsize.
1.4.If this task cannot be executed directly by the core thread, cannot join the wait queue, and cannot create a "non-core thread" to execute directly, and you do not set Rejectedexecutionhandler for the thread pool. The thread pool throws a Rejectedexecutionexception exception, which is where the thread pool refuses to accept the task. (actually throwing the rejectedexecutionexception exception is a default Rejectedexecutionhandler implementation in the Threadpoolexecutor thread pool: AbortPolicy, This will be mentioned later in this article)
2.Once a thread in a thread pool finishes executing a task, it tries to get to the task waiting queue for the next waiting task (all the wait tasks implement the Blockingqueue interface, which, by the interface's literal understanding, is a blocking queue interface), which invokes the poll () waiting for the queue method, and where to stay.
3.When a thread in the thread pool exceeds the Corepoolsize parameter you set, there is a so-called "non-core thread" in the current thread pool. Then, when a thread finishes working on a task, it will be recycled if there is still no new task assigned to it after waiting for keepalivetime time. When the thread pool recycles threads, it treats the so-called "core threads" and "non-core threads" as equal, until the recycle process stops until the number of threads in the thread pools equals the corepoolsize parameter that you set.
infrequently used settings
In the threadpoolexecutor thread pool, there are some infrequently used or even unwanted settings
Allowcorethreadtimeout:
Thread pool Recycling threads only occur when the current thread pool has a greater number of threads than the Corepoolsize parameter, and the recycle process stops when the thread pool is less than or equal to the corepoolsize parameter.
Allowcorethreadtimeout Setup items can require a thread pool: any thread that does not have a task assignment, including "Core threads", is recycled after waiting for KeepAliveTime time:
new ThreadPoolExecutor(5101new ArrayBlockingQueue<Runnable>(1));poolExecutor.allowCoreThreadTimeOut(true);
Here are the effects before setting:
The following are the effects of the settings:
Prestartallcorethreads
We also discussed that when a thread in a thread pool has not reached the value of the Corepoolsize parameter you set, if a new task arrives, the thread pool will create a new thread to run the task, regardless of whether the previously created thread is idle. This description can be expressed in the following:
Prestartallcorethreads sets the number of threads that conform to the Corepoolsize parameter value before the online pool is created, but no tasks are received:
new ThreadPoolExecutor(5101new ArrayBlockingQueue<Runnable>(1));poolExecutor.prestartAllCoreThreads();
Java multithreaded Research 04-Thread pool Usage (Threadpoolexecutor detailed)