Java thread Pool (threadpoolexecutor) principle Analysis and usage __java

Source: Internet
Author: User
Tags cas connection pooling throwable try catch

The concept of "pooling" in our development is not uncommon, with database connection pooling, thread pooling, object pooling, Chang, and so on. Below we mainly for line pool step-by-step to uncover thread pool veil. benefits of using a thread pool

1. Reduce resource consumption
You can reuse the created threads to reduce the consumption caused by thread creation and destruction.
2. Improve response speed
When a task arrives, the task can be executed immediately without waiting for the thread to be created.
3, improve the manageability of the thread
Threads are scarce resources, if created indefinitely, not only consumes system resources, but also reduces system stability, the use of thread pool can be unified allocation, tuning and monitoring the thread pool working principle

First, let's look at how the thread pool is handled when a new task is submitted to the thread pool.
1, thread pool to determine whether the core line Cheng Chili threads are performing tasks. If not, a new worker thread is created to perform the task. If the thread Cheng Chili the core line is performing the task, the second step is performed.
2, the thread pool to determine whether the work queue is full. If the work queue is not full, the newly submitted task is stored in this task column for waiting. If the work queue is full, perform the third step
3, the thread pool to determine whether the threads pool is in the working state. If not, a new worker thread is created to perform the task. If it is full, the saturation policy is given to handle this task thread pool saturation policy

This refers to the saturation strategy of the thread pool, so let's briefly describe what saturation policies are:
AbortPolicy
Default blocking policy for the Java thread pool, do not perform this task, and throw a Run-time exception directly. Remember that Threadpoolexecutor.execute requires a try catch or the program exits directly.
Discardpolicy
Discards directly, the task does not execute, and the null method
Discardoldestpolicy
Discards one of the head's tasks from the queue and executes the task again.
Callerrunspolicy
Executes this command inside the thread that invokes execute, blocking the portal
User-defined rejection policy (most commonly used)
implementation Rejectedexecutionhandler, and define the policy pattern yourself
Let's take threadpoolexecutor as an example to show the workflow flowchart for the thread pool


1, create a new thread to perform a task if the currently running threads are less than corepoolsize (note, To perform this step, you need to obtain a global lock.
2, if the thread that is running is equal to or greater than corepoolsize, the task is added to the blockingqueue.
3, if the task cannot be joined to Blockingqueue (the queue is full), create a new thread in a corepool to handle the task (note that this step requires a global lock).
4, if creating a new thread will cause the currently running thread to exceed maximumpoolsize, the task is rejected and the
Rejectedexecutionhandler.rejectedexecution () method is called. The overall design idea for the
Threadpoolexecutor takes the steps above to avoid getting the global lock as much as possible when executing the Execute () method (which would be a serious scalability bottleneck). After Threadpoolexecutor completes the warm-up (the number of threads currently running is greater than or equal to corepoolsize), almost all execute () method calls are performed step 2, and step 2 does not require a global lock. Critical method Source Analysis

Let's look at the core method added to the thread pool method Execute's source code is as follows:
1. If the currently running thread is less than corepoolsize, create a new thread to perform the task (note that this step requires a global lock).
2. If the running thread is equal to or more than Corepoolsize, the task is added to the blockingqueue.
3. If you cannot join the task Blockingqueue (the queue is full), create a new thread in the Corepool to handle the task (note that you need to obtain a global lock to perform this step).
4. If creating a new thread will cause the currently running thread to exceed maximumpoolsize, the task will be rejected and called
Rejectedexecutionhandler.rejectedexecution () method.
Threadpoolexecutor The overall design approach to the above steps is to avoid getting the global lock as much as possible when executing the Execute () method (which would be a serious scalability bottleneck). After Threadpoolexecutor completes the warm-up (the number of threads currently running is greater than or equal to corepoolsize), almost all execute () method calls are performed step 2, and step 2 does not require a global lock. Key method source code Analysis

Let's look at the core method added to the thread pool method Execute's source code is as follows:

     Executes the given task sometime in the future.
     The task//may execute in a new thread or in a existing pooled thread. If The task cannot is submitted for execution, either because this//executor has been shutdown or becaus
     E its capacity has been reached,//the task are 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 Nullpointer
            Exception if {@code command} is null//public void Execute (Runnable command) {if (command = null)
        throw new NullPointerException (); Proceed in 3 steps:////1.
         If fewer than corepoolsize threads are running, try to//start a new thread with the given command as its Task.  The call to Addworker atomically checks runstate and//Workercount, and so prevents false alarms that would ad
         d//threads it shouldn ' t, by returning false.
         The translation is as follows://Determine if the current number of threads is less than corepoolsize if yes, create a new thread by using the Addword method,///If the new thread creation Exexute method finishes, the task is successfully submitted 2. 
         If a task can be successfully queued, then we still need//to double-check whether we should have added a thread  (because existing ones died since last checking) or that//the pool shut down since entry to this Method. So we//recheck state and if necessary roll back the enqueuing if//stopped, or start a new thread if
         There are none. The translation is as follows://In the first step does not complete the task submission; the status is run and can successfully join the task to the work queue, and then check again if the status//is not running after the task joins the queue (it is possible to execute to the thread pool shutdown) , the runtime is of course required//reject, and then determine whether the current number of threads is 0 (it is possible that the number of threads becomes 0), and if so, add a thread;//3. If We cannot 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.
        The translation is as follows://If you cannot join a task to a work queue, you will try to add a thread to the task, and if it fails, the thread pool is shutdown or the thread pool//has reached saturation, so reject the task//
        int c = Ctl.get (); The number of worker threads is less than the core threads if (Workercountof (c) < corepoolsize) {//Start the new thread directly, True indicates that the Workercount is checked again for less than Corepoo
            Lsize if (addworker (command, True)) return;
        c = Ctl.get (); //If the number of worker threads is greater than or equal to the core thread number//thread is not running and the queue Notfull if (isrunning (c) && Workqueue.offer (com
            Mand) {//Check the running state of the thread again, if it is not running remove the int recheck = Ctl.get () directly from the queue;
            if (! isrunning (Recheck) && Remove (command))//Remove succeeded, reject the non-running task reject (command);
                else if (workercountof (recheck) = = 0)//prevents no active threads in the shutdown state, but there are tasks in the queue that do not perform this particular case. Adding a null task is because the thread pool no longer accepts new tasks in the shutdown state
                Addworker (null, FALSE);
    //If the queue is full or a task that is not running refuses to execute else if (!addworker (command, False)) reject (command); }

Let's continue to see how the Addworker is implemented:

  Private Boolean Addworker (Runnable Firsttask, Boolean core) {//Java Tags retry://Dead cycle fo R (;;)
            {int c = ctl.get ();
            Gets the current thread state int rs = runstateof (c);
            Check If queue empty only if necessary. 
            This logic is a bit of a detour. can be changed to//RS >= shutdown && (rs!= shutdown | | firsttask!= NULL | | workqueue.isempty ()) Logical judgment can be divided into the following situations are not accept new tasks//1, RS > shutdown:--do not accept new tasks//2, RS >= shutdown  ;& firsttask!= null:--does not accept new tasks//3, RS >= shutdown && workqueue.isemppty:--do not accept new tasks// Logical judgment is not valid//1, rs==shutdown&&firsttask!= null: New tasks are not accepted at this time, but the tasks in the queue are still executed//2, rs==shotdown&
            &firsttask = = null: Performs addwork (null,false)//Prevents no active threads in the shutdown state, but there are tasks in the queue that do not perform this particular case. Adding a null task is because the thread pool no longer accepts new tasks if the SHUTDOWN State (Rs >= SHUTDOWN &&! (rs = = SHUTDOWN && firsttask = null &&!
            Workqueue.isempty ()) return false; Dead loops///If the thread pool state is running and there are tasks in the queue that need to be performed for (;;)
                {//Get thread pool centerline number int WC = Workercountof (c);
                    If the capacity is exceeded or the maximum thread pool capacity is not accepting new tasks if (WC >= CAPACITY | | | WC >= (core? corepoolsize:maximumpoolsize))
                return false; Thread security to increase the number of worker threads if (Compareandincrementworkercount (c))//jump out of retry B
                Reak retry;  c = Ctl.get (); Re-read CTL//If thread pool state changes, recycle if (runstateof (c)!= RS) Continue R
                Etry; Else CAS failed due to workercount;
        Retry Inner Loop}}//Go here to show the number of worker threads increased successfully Boolean workerstarted = false;
        Boolean workeradded = false;
        Worker w = null; try {final ReentrantloCK mainlock = This.mainlock;
            w = new Worker (firsttask);
            Final Thread t = w.thread;
                if (t!= null) {//Lock mainlock.lock ();
                    try {//recheck while holding lock.
                    Threadfactory failure or if//Shut down before lock acquired.
                    int c = Ctl.get ();
                    int rs = runstateof (c); Running Status | |
                        Shutdonw the remaining tasks in the cleanup queue if (rs < SHUTDOWN | | (rs = = SHUTDOWN && firsttask = null))
                            {//Check thread state if (t.isalive ())//PreCheck that T-startable
                        throw new Illegalthreadstateexception ();
                        Add the newly started thread to the thread pool Workers.add (w);
           Update thread pool threads and no more than maximum int s = workers.size ();             if (S > largestpoolsize) largestpoolsize = s;
                    Workeradded = true;
                finally {Mainlock.unlock (); //Start the newly added thread, which first executes the firsttask and then constantly takes the task from the queue to execute if (workeradded) {//Execute
                    Threadpoolexecutor Runwoker Method T.start ();
                Workerstarted = true;
                The W is removed from the wokers and the Wokercount if (! workerstarted) is decremented by the "}" finally {//thread startup failure.
        The descending wokercount triggers the Tryterminate method addworkerfailed (W);
    return workerstarted; }

Addworker is followed by Runworker, the first start of the task Firsttask that is initialized, and then the task executes from Workqueue, and waits for KeepAliveTime if the queue is empty

 final void Runworker (Worker w) {Thread wt = Thread.CurrentThread ();
        Runnable task = W.firsttask;
        W.firsttask = null; Allow interrupt W.unlock ();
        Allow interrupts Boolean completedabruptly = true;  try {//if Gettask returns null then the Workercount will be decremented in Gettask, if this decrement operation is handled in Processworkerexit while (Task!= null | |
                (Task = Gettask ())!= null) {W.lock ();
                If pool is stopping, ensure thread is interrupted;  If not, ensure thread isn't interrupted. This//requires a recheck into second case to deal with//Shutdownnow race while clearing
                     Interrupt 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);    }
    }

Let's see how the Gettask is performed

Private Runnable Gettask () {Boolean timedout = false;//Did The last poll ()? Death cycle retry:for (;;)
            {//Get thread pool state int c = Ctl.get ();
            int rs = runstateof (c);
            Check If queue empty only if necessary.
            1.rs > SHUTDOWN So RS is at least equal to stop, then the task in the queue is no longer processed/2.rs = SHUTDOWN so rs>=stop is definitely not established, then you also need to process the tasks in the queue unless the queue is empty  Both of these cases return null so that runwoker exits the while loop, which means the current thread is over, so you must decrement if (Rs >= SHUTDOWN && (rs >= STOP | |
                Workqueue.isempty ()) {//Descending Workercount value decrementworkercount ();
            return null; }//Whether to set timeout when fetching a task from the queue Boolean timed;
            Are workers subject to culling? 1.RUNING Status//2.SHUTDOWN status, but there are tasks in the queue that need to execute for (;;)
                {int WC = Workercountof (c); 1.core thread is allowed to timeout, then threads exceeding corepoolsize must have timed out//2.allowCoreThreadTimeOut = = False && WC >//Corepoolsize, this is generally the case when core thread is not recycled even if it is idle Threads will timed = Allowcorethreadtimeout | |
                WC > corepoolsize; From Addworker you can see that the general WC will not be larger than maximumpoolsize, so it is more concerned about the latter half of the sentence://1. TimedOut = = False First execution loop, fetch task from queue not NULL method return or//poll exception retry//2.timeOut = = True && Amp Timed =//false: Look at the following code Workerqueue.poll timeout timeout is true,//and timed to false, these two conditions are inconsistent can not be set up simultaneously
                (Since there is a timeout so timed is definitely true)//So the timeout does not continue but the return null end thread. if (WC <= maximumpoolsize &&!) (
                TimedOut && timed)) break;
                Workercount Descending, ending current thread if (Compareanddecrementworkercount (c)) return null; c = Ctl.get ();
  Re-read CTL//The thread pool state needs to be checked again because the threads pool of the above procedure may be shutdown if (runstateof (c)!= RS)                  Continue retry; Else CAS failed due to workercount; 
                Retry Inner Loop} try {//1. Fetch a task from the queue with the specified timeout//2.core thread no timeout Runnable r = timed?
                Workqueue.poll (KeepAliveTime, Timeunit.nanoseconds): Workqueue.take ();
                if (r!= null) return R;
            timedout = true;//Timeout} catch (Interruptedexception retry) {timedout = false;//thread interrupted retry }
        }
    }

Below let's see how Processworkerexit works

private void Processworkerexit (Worker W, Boolean completedabruptly) {//Normal Runworker Gettask method Workercount has been reduced by one
        if (completedabruptly) Decrementworkercount ();
        Final Reentrantlock mainlock = This.mainlock;
        Mainlock.lock ();
            try {//additive thread completedtasks completedtaskcount + = W.completedtasks;
        Remove timeout or exception thread Workers.remove (w) from the thread pool;
        finally {Mainlock.unlock ();
        //attempt to stop thread pool tryterminate ();
        int c = Ctl.get (); Runstate is running or shutdown if (Runstatelessthan (c, STOP)) {//thread is not an exception end if (!completedab  Ruptly) {//thread pool minimum idle number, allow core thread timeout is 0, otherwise it is corepoolsize int min = allowcorethreadtimeout ?
                0:corepoolsize; If min = 0 but the queue is not empty make sure there are 1 threads to execute the tasks in the queue if (min = 0 &&!workqueue.isempty ()) MI
                n = 1;Thread pool is not empty then don't worry about it. if (Workercountof (c) >= min) return;
            Replacement not needed}//1. Thread exception exit//2. The string pool is empty, but there are still tasks in the queue that are not executed, see how the Addwoker method handles this situation
        Addworker (null, FALSE); }
    }

The

Tryterminate
Processworkerexit method attempts to call Tryterminate to terminate the thread pool. This method executes after any action that may cause the thread pool to terminate: for example, to reduce wokercount or shutdown to remove a task from the queue.

final void Tryterminate () {for (;;)
            {int c = ctl.get (); The following States are returned directly://1. The thread pool is also in the running state//2.SHUTDOWN State but the task queue is not empty//3.runState >= tidying The thread pool has stopped or stopped if (isrunning (c) | | Runstateatleast (c, tidying) | |
                (Runstateof (c) = = SHUTDOWN &&!workqueue.isempty ()))
            Return
            The following logic can only be continued in the following situations: End thread pool. 1.SHUTDOWN state, when the new task is no longer accepted and the task queue is empty/2.STOP status, when the Shutdownnow method is invoked//Workercount is not 0, the thread pool cannot be stopped, and the threads
            All in idle waiting state//need to interrupt let the thread "wake up" to come, wake up thread can continue to process shutdown signal.
                if (Workercountof (c)!= 0) {//eligible to terminate//Runwoker method W.unlock is to be interrupted, the Gettask method also handles the interrupt.
                Only_one: Here it is only necessary to interrupt 1 threads to handle the shutdown signal.
                Interruptidleworkers (Only_one);
            Return
            Final Reentrantlock mainlock = This.mainlock;
            Mainlock.lock ();
          try {      Enter tidying state if (Ctl.compareandset (c, Ctlof (tidying, 0)) {try {
                    Sub-class Overload: Some resource cleanup work terminated ();
                        Finally {//terminated state Ctl.set (Ctlof (terminated, 0));
                    Continue awaittermination termination.signalall ();
                } return;
            finally {Mainlock.unlock (); }//Else retry on failed CAS}}

Shutdown This method will place the runstate as shutdown, terminating all idle threads. The Shutdownnow method runstate the stop. And the shutdown method, this method terminates all threads. The main difference is that shutdown calls Interruptidleworkers this method, and Shutdownnow actually calls the interruptifstarted method of the worker class:
Their implementation is as follows:

public void Shutdown () {final Reentrantlock mainlock = This.mainlock;
        Mainlock.lock ();
            try {checkshutdownaccess ();
            The thread pool state is set to SHUTDOWN and, if it is already at least this state, returns directly to Advancerunstate (SHUTDOWN);
            Note that this interrupts all idle threads: The threads waiting in the runworker are interrupted → entering the processworkerexit→//tryterminate method guarantees that the remaining tasks in the queue are executed.
            Interruptidleworkers (); OnShutdown ();
        Hook for Scheduledthreadpoolexecutor} finally {Mainlock.unlock ();
    } tryterminate ();
    Public list<runnable> Shutdownnow () {list<runnable> tasks;
    Final Reentrantlock mainlock = This.mainlock;
    Mainlock.lock ();
        try {checkshutdownaccess ();
        Stop status: The new task is no longer accepted and the tasks in the queue are no longer executed.
        Advancerunstate (STOP);
        Interrupts all Threads interruptworkers ();
        Returns a task that has not been performed in the queue.
    tasks = Drainqueue ();
    finally {Mainlock.unlock ();
    } tryterminate (); Return Tasks;
    } private void Interruptidleworkers (Boolean onlyone) {final Reentrantlock mainlock = This.mainlock;
    Mainlock.lock ();
            try {for (Worker w:workers) {Thread t = w.thread;
            W.trylock can acquire a lock, stating that the thread is not running because the task in Runworker will lock first,//thus ensuring that the interrupt must be an idle thread.
                if (!t.isinterrupted () && W.trylock ()) {try {t.interrupt ());
                The catch (SecurityException ignore) {} finally {W.unlock ();
        } if (Onlyone) break;
    finally {Mainlock.unlock ();
    } void Interruptifstarted () {Thread T;  state = = 1 if (getState () >= 0 && (t = thread)!= null &&!t.isinterrupted ()) {try
        {T.interrupt (); The catch (SecurityException ignore) {}}}

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.