Thread Pool Threadpoolexecutor Analysis

Source: Internet
Author: User
Tags throwable

The thread pool. The thread pool is what, say exactly, the thread pool is a form of processing multithreading, managing the creation of threads, the running of tasks, avoiding the resource consumption caused by unlimited creation of new threads, can improve the performance of the application. Very many related operations are inseparable from the thread pool, for example, the encapsulation of network requests in Android applications. The questions to be addressed in this blog post are:

1. How the thread pool works and the process.


To analyze the thread pool's working principle and process, or to start with its source code implementation, the first is the thread is the construction method, what is the construction method. The constructor method is to initialize the member variables, where we can see how it is constructed:

/** * Creates a new {@code Threadpoolexecutor} with the given initial * parameters. * * @param corepoolsize the number of threads to keep in the pool, even * if they is idle, unless {@code a      Llowcorethreadtimeout} is set * @param maximumpoolsize the maximum number of threads to allow in the * pool * @param KeepAliveTime when the number of threads was greater than * the core, this is the maximum time tha     T excess idle threads * 'll wait for new tasks before terminating. * @param unit The time unit for the {@code keepalivetime} argument * @param workQueue the ' queue to ' use for holding Tas  KS before they is * executed.     This queue would hold only the {@code Runnable} * Tasks submitted by the {@code Execute} method. * @param threadfactory the factory to use when the executor * creates a new thread * @param handler the Han Dler to, execution is blocked * because The thread bounds and queue capacities is reached * @throws illegalargumentexception if one of the following holds:         <br> * {@code corepoolsize < 0}<br> * {@code KeepAliveTime < 0}<br> * {@code maximumpoolsize <= 0}<br> * {@code maximumpoolsize < corepoolsize} * @throws Nu  Llpointerexception if {@code WorkQueue} * or {@code threadfactory} or {@code handler} is null */public Threadpoolexecutor (int corepoolsize, int maximumpoolsize, long KeepAliveTime, Timeunit unit, blockingqueue<runnable> work Queue, Threadfactory threadfactory, Rejectedexecutionhandler Han            Dler) {if (Corepoolsize < 0 | |            Maximumpoolsize <= 0 | |            Maximumpoolsize < Corepoolsize | | KeepaliVetime < 0) throw new IllegalArgumentException ();        if (WorkQueue = = NULL | | threadfactory = = NULL | | handler = = NULL) throw new NullPointerException ();        This.corepoolsize = corepoolsize;        This.maximumpoolsize = maximumpoolsize;        This.workqueue = WorkQueue;        This.keepalivetime = Unit.tonanos (KeepAliveTime);        This.threadfactory = threadfactory;    This.handler = handler; }
The first parameter, corepoolsize the number of core threads, maximumpoolsize the maximum number of threads. KeepAliveTime and timeunit non-core thread idle time, more than this setting time will be terminated, Timeunit contains a number of static member variables as units, such as Seconds;blockingqueue task blocking queue, When the number of core thread creation reaches the maximum, the task is first added to the blocking queue. Waiting to run; Threadfactory thread constructs the factory. Often used with defaultthreadfactory, we can also rewrite its Newthread method to implement this class, Rejectedexecutionhandler, when a task is refused to join. will be handed over to this class of processing. Well, the process of construction. It's that simple to initialize some member variables.


Analysis of the time. Starting with the key point, the analysis here begins with the Execute () method:

 /** * Executes the given task sometime in the future.     The task * May, execute in a new thread, or in an existing pooled thread.  * * If The task cannot is submitted for execution, either because this * executor have been shutdown or because its     Capacity has been reached, * the task was handled by the current {@code Rejectedexecutionhandler}. * * @param command the task to execute * @throws rejectedexecutionexception at discretion of * {@code Rejectedexecutionhandler}, if the task * cannot is accepted for execution * @throws NullPointerException I f {@code command} is null */public void execute (Runnable command) {if (command = = null) throw n        EW NullPointerException (); /* * Proceed in 3 steps: * * 1.         If fewer than corepoolsize threads is running, try to * start a new thread with the given command as its first  * Task. The call to Addworker atomically checkS Runstate and * workercount, and so prevents false alarms this would add * threads when it shouldn ' t, by         Returning false. * * 2.         If a task can be successfully queued, then we still need * to double-check whether we should has added a thread * (because existing ones died since last checking) or which * the pool shut down since entry to this Metho D. We * recheck state and if necessary rolled back the enqueuing if * stopped, or start a new thread if T         Here is none. * * 3.  If We cannot the queue task, then we try to add a new * thread.         If it fails, we know we are shut down or saturated * and so reject the task.        */int c = Ctl.get ();            if (Workercountof (c) < corepoolsize) {if (Addworker (command, True)) return;        c = Ctl.get (); } if (IsRunning (c) && workqueue.offer (command)) {int recheck = Ctl.get();            if (! isrunning (Recheck) && Remove (command)) reject (command);        else if (workercountof (recheck) = = 0) Addworker (null, FALSE);    } else if (!addworker (command, False)) reject (command); }
The above execute method, passed in is a runnable, this method is we need to run the task. Below we analyze how execute runs this task, which is the process of execute execution:

1. Assuming that the number of threads in the thread pool is less than the number of core threads, start a new thread to handle this task.

2. Assuming that the core thread is in a non-spare state, the task is inserted into the blocking queue and, when Wired spare, takes its own initiative to run.

3. Assume that the blocking queue task is full. And the current thread is less than the maximum number of threads, the new thread is started. Run the task. Assuming that the maximum number of threads is exceeded, the new task is rejected.

This is the entire code process, and now our team code is analyzed

if (Workercountof (c) < corepoolsize) {            if (addworker (command, True))                return;
Workercountof (c) represents the number of current threads. Assuming that the number is less than corepoolsize, the Addworker (Command,true) method is called, assuming that the Addworker runs successfully and returns True, indicating that the task has finished running. Here we look at the Addworker method:

 Private Boolean Addworker (Runnable Firsttask, Boolean core) {retry:for (;;)            {int c = ctl.get ();            int rs = runstateof (c);            Check If queue empty only if necessary. if (rs >= SHUTDOWN &&!                (rs = = SHUTDOWN && Firsttask = = null &&! workqueue.isempty ()))            return false; for (;;)                {int WC = Workercountof (c);                    if (WC >= Capacity | |                WC >= (Core corepoolsize:maximumpoolsize)) return false;                if (Compareandincrementworkercount (c)) break retry;  c = Ctl.get ();                Re-read CTL if (runstateof (c)! = RS) continue retry; Else CAS failed due to workercount change;        Retry Inner Loop}} Boolean workerstarted = false; Boolean workeradded =False        Worker w = null;            try {w = new Worker (firsttask);            Final Thread t = w.thread;                if (t! = null) {final Reentrantlock mainlock = This.mainlock;                Mainlock.lock ();                    try {//recheck while holding lock.                    Threadfactory failure or if//Shut down before lock acquired.                    int rs = runstateof (Ctl.get ());                        if (Rs < SHUTDOWN | | (rs = = SHUTDOWN && Firsttask = = null)) {if (t.isalive ())//PreCheck that T is startable throw new Illegalthre                        Adstateexception ();                        Workers.add (w);                        int s = workers.size ();                        if (S > largestpoolsize) largestpoolsize = s;                    Workeradded = true; }                }finally {Mainlock.unlock ();                    } if (workeradded) {T.start ();                Workerstarted = true;        }}} finally {if (! workerstarted) addworkerfailed (w);    } return workerstarted; }
Addworker method is longer, we are divided into two pieces, the first for the loop, the second block try .... First block, for loop. The main reason is to infer whether the current can run the task, assuming that it can, then make the following try, pass the condition. able to analyze it. Is the current thread is less than the core thread. Or the current blocking queue is full and the number of threads is less than the maximum number of threads.       Meet these two conditions, the ability to go down. Try inside through the current parameters, a new worker, the worker implements the Runable interface, worker inside through threadfactory constructs a thread to run this task, behind the code, called the T.start (), in fact , the call is that the worker implements the Runable run method. The Run method calls the Runworker () again, and we look at the Runworker method

 final void Runworker (Worker w) {Thread wt = Thread.CurrentThread ();        Runnable task = W.firsttask;        W.firsttask = null; W.unlock ();        Allow interrupts Boolean completedabruptly = true; try {while (task! = NULL | |                (Task = Gettask ()) = null) {W.lock ();                If pool is stopping, ensure thread is interrupted;  If not, the ensure thread is not interrupted. This//requires a recheck in second case to deal with//Shutdownnow race while clearing in                     Terrupt if (Runstateatleast (Ctl.get (), STOP) | | (thread.interrupted () && runstateatleast (Ctl.get (), STOP)))                &&!wt.isinterrupted ()) wt.interrupt ();                    try {beforeexecute (WT, Task);                    Throwable thrown = null; try {task.run ();                    } catch (RuntimeException x) {thrown = x; throw x;                    } catch (Error x) {thrown = x; throw x;                    } catch (Throwable x) {thrown = x; throw new Error (x);                    } finally {AfterExecute (task, thrown);                    }} finally {task = null;                    w.completedtasks++;                W.unlock ();        }} completedabruptly = false;        } finally {Processworkerexit (w, completedabruptly); }    }

First of all we need to know that the entire Runworker method is running in thread threads. Runworker, while loop, lock, the first task is not empty, run this firsttask, when Task.run () runs out, unlocks, and then calls Gettask (). Gettask is removed from the blocking queue to run the task, so here we come to the conclusion. When a thread finishes a task.        The task is removed from the blocking queue to run. The condition of the while loop is that the task is not empty. Or the gettask is not empty, assuming the task is empty. And Gettask is also empty, jump out of the loop, but first see the Gettask () method,

Private Runnable Gettask () {Boolean timedout = false;//Did the last poll () Time out?

for (;;) {int c = ctl.get (); int rs = runstateof (c); Check If queue empty only if necessary. if (Rs >= SHUTDOWN && (rs >= STOP | | workqueue.isempty ())) {Decrementworkercount (); return null; } int WC = Workercountof (c); Is workers subject to culling?

Boolean timed = Allowcorethreadtimeout | | WC > corepoolsize; if (WC > Maximumpoolsize | | (timed && timedout)) && (WC > 1 | | workqueue.isempty ())) {if (Compareanddecrementworkercount (c)) return null; Continue } try {Runnable r = timed?

Workqueue.poll (KeepAliveTime, Timeunit.nanoseconds): Workqueue.take (); if (r! = null) return r; TimedOut = true; } catch (Interruptedexception retry) {timedout = false; } } }


The main function of this method is to remove a task from the queue to run, however. We analyze it carefully. Assuming that Allowcorethreadtimeout is true (that is, agreeing to the core line blocks until those), or when the front thread is non-core, then Timed=true, then. Entering if statement inference, wc>maximupoolsize, this is generally not true. directly see Timed&&timeout,timed=true,timeout as false, directly into the try, the last timeout=true, when the back loop, assuming that the queue task is empty, will run to Compareanddecrementworkercount (c) To reduce the number of threads, then return null, and the thread will terminate, but assuming Allowcorethreadtimeout=false, It calls Workqueue.take directly () and takes out a runnable directly. Assuming that runnable is empty, it will always loop and the thread is stuck here, that is, the core thread is in the spare state.

A new conclusion is drawn here. Assume that the core thread does not have a consent timeout. Then it will always be in the spare state and will not be recycled.

We return to the Execute method again. Part II

if (IsRunning (c) && workqueue.offer (command)) {            int recheck = Ctl.get ();            if (! isrunning (Recheck) && Remove (command))                reject (command);            else if (workercountof (recheck) = = 0)                Addworker (null, FALSE);        }
Assume that the current thread pool is in the execution state, and that the task can be inserted into the queue (since the number of threads here is already equal to the number of core threads.) So inserted into the queue, waiting to be executed). Second inference. Assume that the current thread pool is not in the execution state. Then remove this task, call the Reject method, and assume that the current thread pool has a number of threads 0,addworker (), pass in null and false, that is, do not join a new task, and when a non-core thread is started, the core thread will pass the Gettask () method to remove the task execution. This is the same as the process of analysis above.


Part III

else if (!addworker (command, false))            reject (command);
Start a non-core thread to run the task first. Assuming that the non-core thread reaches the maximum number of threads, the task will not be denied running.




The final conclusion is:

1. Assuming that the number of threads in the thread pool is less than the number of core threads, start a new thread to handle this task.

2. Assuming that the core thread is in a non-spare state, insert the task into the blocked queue. When the thread spare, it will take the initiative to remove the task to run.

3. If the blocking queue task is full and the current thread is less than the maximum number of threads, start a new thread. Running the task, assuming that the maximum number of threads is exceeded, rejects the new task.

Assume that the core thread is not set to a consent timeout. Then the core thread will persist and wait for the task to run immediately.






Thread Pool Threadpoolexecutor Analysis

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.