当前位置:网站首页>How worker threads in the thread pool are recycled

How worker threads in the thread pool are recycled

2022-06-13 07:01:00 Final code lifetime

Click on “ End of life ”, Focus on , Official account

Daily technical dry goods , First time delivery !

1、 Preface

JDK Medium ThreadPoolExecutor Thread pools are familiar to everyone , Some high-frequency interview questions about thread pool , For example, what are the parameters , The meaning of each parameter , When does it work , Work flow and other questions can be answered . And for some not very common thread pool surface test questions appear a little fuzzy , such as : After a thread in the thread pool finishes executing a task, what is to be done next , Wait or be taken back , If it's waiting , So what is the basis of judgment , If it is recycled , So how is it recycled . We must dig deep into these problems ThreadPoolExecutor Source code knowledge , Instead of reciting a few common interview questions , Let's take a look at what the thread does after it finishes executing a task

2、execute(Runnable command)

execute The method is the source of our use of thread pools , Let me take a look at calling execute What did you do after the method

The key to see addWorker() Method , Here we should think of the thread pool as a pool , You can also see from the method name addWorker() Add a worker , So this Worker The object will be put into the pool , We can imagine that this pool must be a collection , such as List,Set,Map Fine

Sure enough Set Make a collection , Then I will put Worder Objects in the Set in , Then let's look at how to add tasks to the thread pool .

We'll see it coming in Runnable The task is packaged into a Worker object , And then Worker Of thread The member properties are copied to Thread t local variable , Let's take a look at it Worker This class

Will find Worker The construction method of will create a new thread by creating a thread factory , And will present this Object assigned to thread Member variables , Rewrote run() Method , As for what the previous figure pointed out thread.start() The startup thread will call Worker object run() Method , Let's focus on run() Method .

3、runWorker(Worker w)

You can see the rewritten from the source code run() Methods mainly call runWorker Method

You can see runWorker In the method , First of all, I will firstTask Assign a value to Runnable task Variable ,firstTask It is the task that the worker thread executes when it runs for the first time , And then we will firstTask=null, namely firstTask It's only going to be executed once . Next, we'll enter while condition loop , If while The conditional loop is not satisfied , Finally, it will enter finally Medium processWorkerExit Thread to exit , From the thread pool Set in remove Threads . So we can focus on while In terms of , The first condition task != null It is used to judge the task of the first run , hinder getTask() Method , Next let's see getTask() Method , have a look getTask() When the method returns to us null, It represents this while The conditions are over , Will also enter our processWorkerExit() Thread exit method

We can see that there are two places back null, One is when the thread pool state is STOP,TIDYING, TERMINATED, Or is it SHUTDOWN And the work queue is empty , So it's going to return null,decrementWorkerCount() Reduce the number of worker threads 1. The thread pool abort status is not considered here for the time being , Let's assume that the thread pool is always RUNNING state , Then it will enter the second return null Judgment condition . The second place is back null Is the condition of :1. Number of worker threads in the thread pool > Maximum number of threads or ( Greater than the number of core threads and Worker thread lifetime has timed out ) 2. Number of threads > 1 or The queue is already empty At the same time meet the conditions 1,2 when , Call again CAS Deduct the number of threads , Here's why we need to use CAS Deduction thread , Because it prevents two threads from satisfying the condition at the same time , Then deduct the number of threads , This will result in fewer threads . For example, the number of core threads is 4, The current number of threads is 5 individual , Then there are two threads to judge the condition , Find satisfaction at the same time , Then both threads will deduct , become 3, You should have kept the number of core threads to 4 Of . So using CAS Operation to deduct the number of core threads , If the deduction is successful , Then return to null, It will be over runWorker() Methods while Conditions . Then enter finally Area , Exit thread

The previous analysis returns to the second place null This means that the thread normally executes a task , And then from getTask() Access to task , When the acquisition task is null when , The thread will exit , Remove... From the thread pool . Next, let's analyze the status of a process pool STOP,TIDYING, TERMINATED, Or is it SHUTDOWN When the work queue is empty , return null The situation of .

4、 call shutdown(), To terminate the thread

When calling shutdown() When the method is used , The thread pool will wait for the thread that is executing the task and needs to destroy the task in the blocking queue after it is completed , And no longer accept new tasks . Follow shutdownNow() The difference is ,shutdownNow Method whether the thread is executing or idle, it will interrupt , Returns outstanding tasks in the blocking queue , Blocking the elements in the queue will no longer be executed

Maybe netizens here will have questions , How to judge whether the thread is idle ???

We can see interruptIdleWorkers Method , Before signaling an interrupt to a thread , Need to get tryLock() Acquire exclusive lock , To perform t.interrupt() Method , Let's go back to runWorker() Method

You can see if getTask() Return not to null, Will perform the task , You will get the exclusive lock , Then the thread executing the task cannot send an interrupt message . Unless the task is completed , Release the lock . that interruptIdleWorkers Medium w.tryLock() To get the lock , Send an interrupt signal

3.1 The task is just finished , Release the lock , Enter into while Conditional statements

Enter again to while In the judgment conditions of . Let's see getTask() Method returns... In the first place null The place of

return null The condition of requires two , One is shutdown state , Another is that the queue is empty , No task ( Not for now stop state ). If there are still tasks in the queue , It will call poll perhaps take Access to task

Here netizens may think that the thread is already in the interrupt state ? So called poll and take When the method is used , Should keep throwing InterruptedException Exception is right . If the AQS Familiar words , It should be conceivable that this would not happen , Let's see poll and task Method called

Although it will throw an interrupt exception , But the thread interrupt status will be reset , That is, the next thread is not in an interrupted state , You can continue to obtain task execution , Until the queue is empty . The queue is empty , The thread pool status is shutdown state , It will return at last null.

3.2 If the thread itself is blocked

If the thread itself is blocked in getting the task , then shutdown Send an interrupt signal , Throw interrupt exception , Go to the first place again to judge the condition , Then logic is like 3.1 similar , Will determine whether the queue is empty , If it is not empty , Then continue to call poll and take Access to task , The interrupt state of the thread will also be reset when the thread is first retrieved , You can get the task normally next time , Until the queue is empty , The thread pool state is zero shutdown state , return null.

5、 summary

in general ,ThreadPoolExecutor Recycling threads are waiting getTask() Unable to get task , return null when , call processWorkerExit Methods from Set Collection remove Drop thread ,getTask() return null It is divided into 2 Two scenarios :

1. The thread completes the task normally , And have waited for more than keepAliveTime Time , Greater than the number of core threads , So it will return null, End the outer layer runWorker Medium while loop

2. When calling shutdown() Method , Will set the thread pool state to shutdown, And you need to wait for the task being executed to finish , The task in the blocking queue cannot be returned until it is completed null

At work , I've always believed that programming code is not the most important , What matters is the programming thinking developed at work .

PS: Prevent missing this article , You can like it , It's easy to browse and search

原网站

版权声明
本文为[Final code lifetime]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/164/202206130649129022.html