Benefits: Threads are scarce resources, if created indefinitely, will not only consume system resources, but also reduce the stability of the system, reasonable use of thread pool to uniform distribution, tuning and monitoring, there are the following benefits:
1, reduce the consumption of resources;
2, improve the response speed;
3, improve the manageability of threads.
The executor framework, introduced in Java1.5, decouples the submission and execution of tasks by defining tasks and then submitting them to the thread pool, regardless of how the task executes, which thread executes it, and when it executes.
Demo
1. Executors.newFixedThreadPool(10)
initialize a thread pool containing 10 threads executor;
2, through the executor.execute
method to submit 20 tasks, each task print the current thread name;
3. The life cycle of the thread responsible for executing the task is managed by the executor framework;
Threadpoolexecutor
Executors is the factory class of the Java thread pool, which allows you to quickly initialize a thread pool that meets the needs of your business, such as Executors.newFixedThreadPool
a method that can generate a pooled number of threads with fixed threads.
Its essence is to initialize a Threadpoolexecutor object with different parameters, the specific parameters are described as follows:
Corepoolsize
The number of core threads in the thread pool, when a task is submitted, the thread pool creates a new thread to perform the task until the current number of threads equals corepoolsize, and if the current number of threads is corepoolsize, the task that continues to commit is saved to the blocking queue, waiting to be executed If the Prestartallcorethreads () method of the thread pool is executed, the thread pool creates and starts all core threads in advance.
Maximumpoolsize
The maximum number of threads allowed in the thread pool. If the current blocking queue is full and the task continues to be submitted, a new thread is created to perform the task, provided that the current number of threads is less than maximumpoolsize;
KeepAliveTime
The time at which the thread is idle, that is, when the thread does not have a task to execute, the time to survive; By default, the parameter is only useful if the number of threads is greater than corepoolsize;
Unit
The unit of KeepAliveTime;
WorkQueue
The blocking queue used to hold the task waiting to be executed, and the task must implement the Runable interface, which provides the following blocking queue in the JDK:
1. Arrayblockingqueue: Bounded blocking queue based on array structure, sorting tasks by FIFO;
2, Linkedblockingquene: Based on the chain list structure of the blocking queue, according to FIFO sorting tasks, throughput is usually higher than arrayblockingquene;
3, Synchronousquene: A blocking queue that does not store elements, each insert operation must wait for another thread to invoke the remove operation, otherwise the insert operation is always in a blocked state, and throughput is usually higher than linkedblockingquene;
4, Priorityblockingquene: a priority of the unbounded blocking queue;
Threadfactory
The factory that creates the thread, through a custom thread factory, can set a name for each new thread that has a recognized thread.
Handler
The saturation policy of the thread pool, when the blocking queue is full and there are no idle worker threads, if you continue to submit the task, you must take a policy to handle the task, and the thread pool provides 4 strategies:
1, AbortPolicy: Directly throws the exception, the default policy;
2. Callerrunspolicy: Perform the task with the caller's thread;
3, Discardoldestpolicy: Discard the first task in the blocking queue, and perform the current task;
4, Discardpolicy: direct discard task;
It is also possible to implement the Rejectedexecutionhandler interface based on the application scenario, customizing the saturation strategy, such as logging or persisting the task that the storage cannot handle.
Exectors
The Exectors factory class provides the initialization interface for the thread pool, mainly in the following ways:
Newfixedthreadpool
Initializes a thread pool with a specified number of threads, where corepoolsize = = Maximumpoolsize, using Linkedblockingquene as the blocking queue, but does not release the thread when the thread pool has no executable task.
Newcachedthreadpool
1. Initialize a thread pool that can cache threads, default cache 60s, thread pool threads can reach Integer.max_value, i.e. 2147483647, internal use synchronousqueue as blocking queue;
2. Unlike the thread pool created by Newfixedthreadpool, Newcachedthreadpool automatically frees thread resources when there is no task execution, when the thread is idle for more than KeepAliveTime, and when a new task is submitted, if there are no idle threads, Creates a new thread to perform the task, which results in a certain amount of system overhead;
Therefore, when using this thread pool, be careful to control the number of concurrent tasks, otherwise creating a large number of threads can cause serious performance problems.
Newsinglethreadexecutor
There is only one thread in the initialized thread pool, and if the thread ends abnormally, a new thread is recreated to continue the task, and the only thread can guarantee the order in which the submitted tasks are executed, using Linkedblockingqueue as the blocking queue internally.
Newscheduledthreadpool
The initialized thread pool can periodically perform the submitted tasks within a specified time, and in the actual business scenario, the thread pool can be used to synchronize data periodically.
Implementation principle
In addition to Newscheduledthreadpool's internal implementation of a special point, several other thread pools are based on the Threadpoolexecutor class implementation.
Thread pool Internal state
The Atomicinteger variable ctl is very powerful: it uses a low 29-bit representation of thread pool threads, and a high 3-bit to represent the running state of the thread pools:
1, RUNNING: -1 << COUNT_BITS
, that is, high 3 bits is 111, the state of the thread pool will receive new tasks, and processing the task in the blocking queue;
2, SHUTDOWN: 0 << COUNT_BITS
, that is, high 3 BITS is 000, the status of the thread pool will not receive new tasks, but will handle the task in the blocking queue;
3, STOP: 1 << COUNT_BITS
, that is, the high 3 bit is 001, the thread of this state will not receive new tasks, will not handle the task in the blocking queue, and will interrupt the running task;
4, tidying: 2 << COUNT_BITS
, namely high 3 bit is 010;
5, TERMINATED: 3 << COUNT_BITS
, namely high 3 bit is 011;
Task Submission
The thread pool framework provides two ways to submit tasks, choosing different ways to meet different business requirements.
Executor.execute ()
The task submitted through the Executor.execute () method must implement the Runnable interface, and the task submitted by this method cannot get the return value, so it is not possible to determine whether the task was successfully executed.
Executorservice.submit ()
The task that is submitted by the Executorservice.submit () method can get the return value that the task finished executing.
Task execution
When a task is submitted to the thread pool, what does the thread pooling do with the task?
Execute implementation
The specific implementation process is as follows:
1, the Workercountof method according to the low 29 bits of the CTL, get the thread pool current number of threads, if the number of threads is less than corepoolsize, then execute Addworker method to create a new thread execution task, otherwise execute step (2);
2. If the thread pool is in the running state and the committed task is successfully placed in the blocking queue, perform step (3), otherwise perform step (4);
3, again check the status of the thread pool, if the thread pool is not running, and successfully remove the task from the blocking queue, then perform the Reject method processing task;
4, execute the Addworker method to create a new thread execution task, if Addwoker execution fails, then execute reject method processing task;
Addworker implementation
As you can see from the implementation of the method execute: Addworker is primarily responsible for creating new threads and performing tasks, the code is implemented as follows:
This is just the first half of the Addwoker method implementation:
1, judge the status of the thread pool, if the thread pool state value is greater than or so shutdown, then do not process the submitted task, directly return;
2, through the parameter core to determine whether the currently created thread is the core thread, if the core is true, and the current number of threads is less than corepoolsize, then jump out of the loop, start creating a new thread, the implementation is as follows:
The worker thread of the thread pool is implemented by the Woker class and, under the guarantee of the Reentrantlock lock, inserts the Woker instance into the HashSet and initiates the thread in Woker, where the worker class is designed as follows:
1, inherits the Aqs class, can conveniently realize the work thread the abort operation;
2, realizes the Runnable interface, can carry on itself as a task in the worker thread execution;
3, the currently submitted task Firsttask as a parameter to the construction method of the worker;
From the construction method implementation of the Woker class, you can find that when thread factory creates thread thread, the Woker instance itself is passed as a parameter, and when the Start method is executed, the worker's Runworker method is executed.
Runworker implementation
The Runworker method is the core of the thread pool:
1, after the thread starts, the lock is released through the Unlock method, the state of Aqs is set to 0, which indicates the interruption of operation;
2, get the first task Firsttask, execute the task of the Run method, but before the execution of the task, will be a lock operation, the task will release the lock after execution;
3, before and after the implementation of tasks, can be customized according to business scenarios BeforeExecute and AfterExecute methods;
4, Firsttask after the completion of execution, through the Gettask method to get the waiting task from the blocking queue, if there is no task in the queue, the Gettask method will be blocked and suspended, does not consume CPU resources;
Gettask implementation
The entire gettask operation is done under spin:
1, Workqueue.take: If the blocking queue is empty, the current thread will be suspended waiting, when a task in the queue is joined, the thread is awakened, the Take method returns the task, and executes;
2, Workqueue.poll: If in the KeepAliveTime time, the blocking queue or no task, then return null;
Therefore, threads implemented in the thread pool can execute tasks submitted by the user all the time.
Future and callable implementation
The task that is submitted by the Executorservice.submit () method can get the return value that the task finished executing.
In the actual business scenario, the future and callable are basically paired, and callable is responsible for producing the results, and the future is responsible for obtaining the results.
1. The callable interface is similar to runnable, except that runnable has no return value.
2, callable task in addition to return the normal results, if an exception occurs, the exception will be returned, that is, the future can get the results of asynchronous execution of the task;
3, the Future.get method will cause the main thread to block until the callable task execution is completed;
Submit implementation
The callable task submitted through the Submit method is encapsulated into a Futuretask object.
Futuretask
1, Futuretask in different stages have different states state, initialized to new;
2, the Futuretask class implements the Runnable interface, so that the Executor.execute method can be submitted futuretask to the thread pool waiting to be executed, the final execution is futuretask the Run method;
Futuretask.get implementation
The main thread is blocked internally by the Awaitdone method, which is implemented as follows:
1. If the main thread is interrupted, the interrupt exception is thrown;
2, Judge Futuretask current state, if greater than completing, indicating that the task has been completed, the direct return;
3, if the current state equals completing, indicating that the task has been executed, then the main thread only through the yield method to make up the CPU resources, waiting for it to become normal;
4, the current thread is encapsulated through the Waitnode class and added to the waiters linked list through unsafe;
5. Finally suspend the thread through the Locksupport park or Parknanos;
Futuretask.run implementation
The Futuretask.run method is executed in the thread pool, not the main thread
1, through the implementation of the callable task call method;
2. If call execution succeeds, the result is saved by set method;
3, if call execution has an exception, the exception is saved through SetException;
Set
SetException
In the set and SetException methods, the Futuretask state is modified through unsafe, and the Finishcompletion method is used to notify the main thread that the task has been completed;
Finishcompletion
1. When executing the Get method of Futuretask class, the main thread is encapsulated into Waitnode node and stored in the Waiters chain list;
2, Futuretask task after completion, through the unsafe set waiters value, and through Locksupport class Unpark method wakes the main thread;
Let's just say that the Java thread pool is actually very simple to implement.