Thread pool ThreadPoolExecutor
- What is it: Workers' sweatshop
- What's the use: reduce resource consumption and facilitate thread management
- How to play: play with your new thread pool
Thread pool principle
Working principle of thread pool (advantages and disadvantages)
When there is no thread pool, compare it with the wired process pool. It solves the problem of resource allocation, the idea of pooling, maximizes income, minimizes risk, and unifies the way of resource management.
Five statuses of thread pool (run, shutdown, Stop, dying, terminated)
Thread pool state transition (changes in shutdown, shutdown now and workerQueue)
7 parameters (core, max, keepAliveTime, unit, workerQueue, factory, rejectHandler)
4 reject policies (ACDD)
I don't know what the above is: please go out and turn left:
https://blog.csdn.net/weixin_43801418/article/details/120396484
Basic method
Construction method - > 7 parameters
Small function functions, many of which operate around ctl
runStateOf,workerCountOf,ctlOf
Worker wrapper class, run()
Core method
execute
Submit task process: method of receiving task
1,The task is commond,A request comes in the thread pool 2,Judge whether the current number of workers is less than core,call addWorker(command, true) Successful, return directly Failed. It may be a concurrency problem. Other threads have completed this task; or Thread state change, non running state 3,Try to put workerQueue 1)Status modified non running,Remove the current task and execute the reject policy Success: the task has not been consumed (still in use) workerQue Medium) Failed: after submitting, the shutdown() shutdownNow()Before, it is processed by the threads in the thread pool. 2)still running State, judgment ctl The number of threads is 0, addWorker,At least one thread is working 4,Last direct addWorker(command, false),use max judge Failed: reject(command)
Is worker an instance object or a task?
addWorker
Add new worker s and new methods
Part I: two for spins to judge the thread status and the number of worker s, and the process of taking tokens
Part II: new Worker(firstTask); For incoming tasks, the number of threads is managed by the thread pool itself
In the shutdown state, there are tasks in the workerQueue task queue, and the tasks to be executed are null = > new workers can be added to execute threads
1,Judgment status: 1)running state √ 2)shutdown,workerQueue Not empty, firstTask Empty √ 2,judge woker Number, workerCount 1)wc exceed capacity,exceed core or max => return false 2)wc with cas Method plus 1 to try to get a token Success: get the token and go to the next process Failed: the current thread status changes and needs to be retried (re judge whether the status meets the requirements) 3,new Worker(firstTask),There are threads, and we will do this later worker Judge whether it is legal. 4,use mainLock Global lock start Judge whether the wire pool is① running Status② shutdown And the task queue is alive and nothing new comes in. no problem workers Set Join this worker Go in and work. Release lock 5,last worker join set The aftermath of failure. mainLock 1)yes ctl Minus one 2)set take worker Clear out
runWorker
worker startup
1,initialization wt,task,Exclusive lock lock(-1 -> 0) 2,getTask from workQueue Apply for task 3,open lock, 1)Judging that the thread is dead, STOP After that, the marking thread is interrupted 2)Hook methods, like transactions, can implement pre notification by subclasses Perform tasks, run 3)Hook methods, like transactions, can implement subsequent notifications by subclasses 4,Untie lock(release worker Non reentrant lock) 5,If there are exceptions, handle them uniformly, otherwise exit normally
be careful:
1. processWorkerExit() method, destroy the thread.
2. The while loop continuously obtains the task through the getTask() method.
3. Threads that do not work are blocked unless the thread pool is ready to end
getTask
1. Obtain the task process from the workerQueue; 2. Also responsible for recycling threads
Generally, you can get the task normally. In several cases, you can't get the desired result (null)
return null There are several situations:( State,workerCount) 1,rs >= STOP 2,shutdown And workerQueue Empty 3,wc > max 4,wc > core && overtime Timeout factor: allowCoreTimeOut cas Mode reclaim thread( wc Too large, current task timed out)
processWorkerExit
When the worker exits the process, it will always be called in runWorker.
Because there are many possibilities of thread destruction, the thread pool also needs to judge what caused the destruction, whether to change the current state of the thread pool, and whether to reassign threads according to the new state.
private void processWorkerExit(Worker w, boolean completedAbruptly) { 1,normal or Abnormal exit 1)Abnormal exit: ctl-1 2)Normal exit: take mainLock;set Remove the worker,Record complete task quantity 2,tryTerminate(); Enter the logic to close the thread pool 3,Exit normally, leaving the last thread for the thread 1)minimum worker The number can be at least one worker You can continue to work 2)workerCountOf(c) >= min Then it is safe to continue the exit logic 4,Abnormal exit: because there are many possibilities of thread destruction, the thread pool also needs to judge what caused the destruction, whether to change the current state of the thread pool, and whether to reassign threads according to the new state.
shutdown & shutdownNow
Thread shutdown process
shutdown does only two things
1) Modify the thread pool status to shutdown
2) Mark all idle workers as interrupted and tell them it's time to stop work
1,advanceRunState: adopt cas Force setting status to SHUTDOWN 2,Acquired worker 3,Interrupt idle thread plus mainLock Traverse all worker Lock them separately and give them to all getTask Medium blocking (in take/poll Status) worker Make interrupt mark release mainLock 4,Release global lock mainLock 5,tryTerminate();
shutdownNow is just an additional return method to take out the unprocessed tasks in the workQueue for processing
1,advanceRunState: adopt cas Force setting status to SHUTDOWN 2,Acquired worker 3,Interrupt idle thread plus mainLock Traverse all worker Lock them separately and give them to all getTask Medium blocking (in take/poll Status) worker Make interrupt mark release mainLock 4,tasks = drainQueue(); 5,Release global lock mainLock 6,tryTerminate(); 7,return tasks;
tryTerminate
1,Entry spin 1)running 2)Another thread is TIDYING -> TERMINATED 3)shutdown And workQueue Not empty runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty() 2,Ways to interrupt lazy employees. if (workerCountOf(c) != 0) { Execute as long as there are employees in the thread pool interruptIdleWorkers 3,the last one worker be responsible for 0,Lock mainLock 1,Set status to TIDYING 2,Set status to TERMINATED 3,termination.signalAll(); Notify the external thread to wait for the thread pool to become terminated state 0,release mainLock
reference resources
https://tech.meituan.com/2020/04/02/java-pooling-pratice-in-meituan.html