Java thread pool Threadpoolexecutor usage and Analysis (iii)-Termination thread pool principle

Source: Internet
Author: User
Tags cas terminates

Related Articles Directory:

java thread pool threadpoolexecutor usage and analysis (i)

java thread pool threadpoolexecutor usage and Analysis (ii)-execute () principle

java thread pool threadpoolexecutor usage and Analysis (iii)-Termination thread pool principle

The following is the directory outline for this article:

One, shutdown ()--Gentle termination thread pool

Interruptidleworkers ()--Interrupt idle worker

Tryterminate ()--try to terminate the thread pool

Second, Shutdownnow ()--Tough termination thread pool

Interruptworkers ()--interrupts all worker

Iii. awaittermination ()-Waiting for thread pool to terminate

There are two main ways to terminate a thread pool: shutdown () and Shutdownnow ().

The shutdown () post-thread pool becomes the shutdown state, where new tasks are not received, but tasks that are running and waiting to be processed in the blocking queue are processed.

The Shutdownnow () post-thread pool becomes a stop state, where new tasks are not received, the tasks waiting in the blocking queue are no longer processed, and the worker threads that are being processed are also attempted to break.

The following is an analysis of several termination methods for the thread pool, based on the JDK 1.7

One, shutdown ()--Gentle termination thread pool
/** * Initiates an orderly shutdown in which previously submitted * tasks is executed, but no new tasks would be accepted. * Invocation have no additional effect if already shut down. * Start an orderly shutdown in which the previously submitted task will be executed (containing the execution, in the blocking queue), but the new task will be rejected * If the thread pool is already shutdown, calling this method will have no additional effect * * <p>this method does not  Wait for previously submitted the tasks to * complete execution. Use {@link #awaitTermination awaittermination}. * The current method does not wait until the end of the previously submitted task execution, you can use Awaittermination () * * @throws SecurityException {@inheritDoc} */public void Shutdown () {fin    Al Reentrantlock mainlock = this.mainlock; Mainlock.lock ();                Lock try {//To determine if the caller has permission shutdown thread pool checkshutdownaccess ();                cas+ loop sets the thread pool status to SHUTDOWN advancerunstate (SHUTDOWN);                Interrupts all idle threads interruptidleworkers (); OnShutdown (); Hook for Scheduledthreadpoolexecutor} finally {Mainlock.unlock ();//unlock}//try to terminate the thread pool Tryterm Inate ();}

Shutdown () execution process:

1, locked,mainlock is the thread pool of the main lock, is a reentrant lock, when you want to operate workers set this to keep the thread of hashset, need to first obtain mainlock, and when to deal with Largestpoolsize, Completedtaskcount This type of statistical data requires first obtaining Mainlock

2. Determine if the caller has permission shutdown thread pool

3. Using CAs operation to set the thread pool state to Shutdown,shutdown will no longer receive new tasks

4. Interrupt all Idle Threads interruptidleworkers ()

5, OnShutdown (), scheduledthreadpoolexecutor in the implementation of this method, you can do some processing in the shutdown ()

6. Unlocking

7. Attempt to terminate thread pool tryterminate ()

The most important steps you can see for the shutdown () method are: Update the thread pool status to shutdown, break all idle threads ,tryterminated () attempt to terminate the thread pool

So, what is a free thread? How does the Interruptidleworkers () interrupt the idle thread?

/** * Interrupts threads that might being waiting for tasks (as * indicated by not being locked) so they can check for * term Ination or configuration changes. Ignores * securityexceptions (in which case some threads may remain * uninterrupted). * Interrupts the thread waiting for the task (unlocked), after the interrupt wakes up, can determine whether the thread pool state changes to decide whether to continue * * @param onlyone If true, interrupt at the most one worker.  This was * called only from tryterminate when termination was otherwise * enabled but there was still other workers. In the case, at * Most one waiting worker is interrupted to propagate shutdown * signals in case (lest) all threads be Curr ently waiting. * Interrupting any arbitrary thread ensures that newly arriving * workers since shutdown began would also eventually exit.  * To guarantee eventual termination, it suffices to always * interrupt only one idle worker, but shutdown () interrupts all * Idle workers so redundant workers exit promptly, not * waiting for a straggler task to finish. * * Onlyone If true, up to interrupt a worker * only if the termination process has started, but when the thread pool has a worker thread, the Tryterminate () method makes a call that calls Onlyone to True * (the terminating process has started to refer to the shutdown state and workqueue is empty, or the stop state) * In this case, At most one worker is interrupted, in order to propagate the shutdown signal so that all the threads are waiting * to ensure that the thread pool eventually terminates, this operation always interrupts an idle worker * and shutdown () interrupts all idle workers to ensure that the idle thread exits in a timely manner */    private void Interruptidleworkers (Boolean onlyone) {final Reentrantlock mainlock = This.mainlock; Mainlock.lock ();                        Lock try {for (Worker w:workers) {Thread t = w.thread;                if (!t.isinterrupted () && W.trylock ()) {try {t.interrupt ();                } catch (SecurityException ignore) {} finally {W.unlock ();        }} if (Onlyone) break; }} finally {Mainlock.unlock ();//Unlock}}

Interruptidleworkers () First acquires the Mainlock lock, because to iterate over the workers set, you need to make two judgments before interrupting each worker:

1, whether the thread has been interrupted, is not doing anything

2, Worker.trylock () is successful

The second judgement is more important, because the worker class in addition to the implementation of the runnable, but also inherit the Aqs, itself is a lock, the concrete visible Threadpoolexecutor internal class worker parsing

Trylock () invokes the Tryacquire () method implemented by the worker itself, which is also an attempt to acquire a lock that the subclass needs to implement AQS

protected Boolean tryacquire (int unused) {    if (compareandsetstate (0, 1)) {         Setexclusiveownerthread ( Thread.CurrentThread ());         return true;    }    return false;}

Tryacquire () first tries to aqs the state from 0-->1, returns true to indicate that the lock was successful, and sets the current thread as the owner

You can see that compareandsetstate (0, 1) tries to acquire the lock only once, not every state+1, but 0-->1, stating that the lock is not reentrant

But why should Worker.trylock () get the worker's lock?

This is one of the values of the Woker class, which controls thread interruption

The Runworker () method requires Worker.lock () lock each time it gets to Task,task.run (), and unlocks after the run is completed, that is, the worker that is running the task is on the worker lock.

The worker lock needs to be trylock () before the interruptidleworkers () interrupt, which means that the worker being run cannot be interrupted because Worker.trylock () fails and the lock is non-reentrant

therefore shutdown () sends an interrupt signal only to the idle thread that can acquire the worker lock (which is Gettask () from Workqueue, at which time the worker does not locking)

This allows the worker to be divided into:
1. Idle worker: worker who is getting a task from the Workqueue blocking queue
2. Working worker: worker who is Task.run () performing a task

The worker that is blocking the Gettask () Gets the task will throw interruptedexception when it is interrupted, no longer blocking the fetch task

After capturing the interrupt exception, it will continue to loop to Gettask () to determine the logic of the thread pool state at the beginning, when the thread pool is shutdown state, and workqueue.isempty, return null, the worker thread exits the logic

In some cases, multiple workers are running at Interruptidleworkers () and will not be signaled, assuming Workqueue is not empty at this time

Then when more than one worker runs, it will go to Workqueue to block the fetch task, get to the execution of the task, not get it, if it is the core thread, will always Workqueue.take () blocked, the thread cannot terminate, because Workqueue is empty, and will not receive new tasks after shutdown.

This requires an interrupt signal after shutdown ().

Doug Lea, the great God, cleverly planted tryterminated () attempt to terminate the thread pool at all possible places where the thread pool was terminated, and in which it was judged that if the thread pool had entered the termination process, no task was waiting to be executed, but the thread pool was also wired, the interrupt woke up an idle thread

Shutdown () also calls the Tryterminated () method at the end of the process, and looks at the logic of this method:

/** * Transitions to TERMINATED state if either (SHUTDOWN and pool * and queue empty) or (STOP and pool empty). If otherwise * eligible to terminate but workercount are nonzero, interrupts an * idle worker to ensure that shutdown Signa LS Propagate. This * method must is called following any action the might make * termination possible--reducing worker count or Remov ing tasks * from the queue during shutdown. The method is non-private to * Allow access from Scheduledthreadpoolexecutor. * * The thread pool becomes terminated in the following situations * shutdown and the running worker and Workqueue queue are empty * stop and no running worker * * This method must be in any thread pool that may cause Termination of the case is called, such as: * Reduce number of worker * shutdown when removing a task from a queue * This method is not private, so the subclass Scheduledthreadpoolexecutor is allowed to call */final void Trytermi Nate () {//This for loop is primarily used in conjunction with CAS judgment to enter the shutdown thread pool operation for (;;)                {int c = ctl.get (); /** * thread pool needs to be terminated * If either of the following 3 conditions is True,return, does not terminate * 1, is still in the running state * 2, the status is tidying, or TERMINATED, has been terminated       After * 3, SHUTDOWN and Workqueue not empty  */if (isrunning (c) | | |            Runstateatleast (c, tidying) | |            (Runstateof (c) = = SHUTDOWN &&! workqueue.isempty ()))                Return /** * Only the shutdown state and workqueue are empty, or the stop state can perform to this step * if the thread pool is still wired (running task, waiting for Task) * Interrupt wakes up an idle wor for a task that is waiting.  Ker * Wake up again to determine the thread pool status, will return NULL, enter the PROCESSWORKEREXIT () process */if (Workercountof (c)! = 0) {//Eligible To terminate qualifying termination interruptidleworkers (Only_one);        Interrupts the idle task in the Workers collection, the parameter is true, and only one return is interrupted; }/** * If the status is Shutdown,workqueue is also empty, the running worker also has no, start terminated */FINAL Reentrantlock Main        Lock = This.mainlock;        Mainlock.lock (); try {//cas: The CTL of the thread pool becomes tidying (all tasks are terminated, Workcount is 0, the terminated () method is invoked for this state), the CTL changes will fail, and the For loop if (CT                 L.compareandset (c, Ctlof (tidying, 0))) {try {terminated ();//requires subclass implementation}           finally {         Ctl.set (Ctlof (TERMINATED, 0)); Convert the CTL of the thread pool into terminated termination.signalall ();            Wake calls Thread Awaittermination ()} Return waiting for the thread pool to terminate;        }} finally {Mainlock.unlock (); }//Else retry on failed CAS//If the CAS above evaluates to False, loop again}}

Tryterminate () execution process:

1. Determine if the thread pool needs to enter the termination process (only if the shutdown state +workqueue.isempty or stop State is required)

2, determine whether the thread pool is also wired, there is interruptidleworkers (only_one) attempt to interrupt an idle thread (it is this logic can again send interrupt signal, interrupt blocking on the thread to get the task)

3, if the status is Shutdown,workqueue also is empty, the running worker also did not have, began terminated

Locks the thread pool to the tidying state, then calls the terminated () that needs to be implemented by the subclass, the last thread pool is terminated state, and wakes up all the threads waiting for the thread pool to terminate this condition

Second, Shutdownnow ()--Tough termination thread pool
/** * Attempts to stop all actively executing tasks, halts the processing tasks, and waiting a list of the TA SKS * that were awaiting execution. These tasks is drained (removed) * from the task queue upon return from this method. * Try to stop all active executing tasks, stop waiting for task processing, and return the task list that is waiting to be executed * This task list is drained (removed) from the task queue * <p>this method does not wait for actively ex  ecuting tasks to * terminate. Use {@link #awaitTermination awaittermination} to * do.  * This method does not have to wait until the end of the task being executed, to wait for the thread pool to terminate can use Awaittermination () * <p>there is no guarantees beyond best-effort attempts to stop  * Processing actively executing tasks. This implementation * cancels tasks via {@link-thread#interrupt}, so-any task-that * fails to respond-interrupts may NE ver terminate. * In addition to trying to stop a running task, there is no guarantee * The cancellation task is implemented through Thread.Interrupt (), so any task that fails to respond to an outage may never end * * @throws SecurityException {@    Inheritdoc} */public list<runnable> Shutdownnow () {list<runnable> tasks; Final Reentrantlock Mainlock = This.mainlOck; Mainlock.lock ();                Lock try {//To determine if the caller has permission shutdown thread pool checkshutdownaccess ();                cas+ loop sets the thread pool status to stop advancerunstate (stop);                Interrupts all threads, including the Interruptworkers () that is running the task; tasks = Drainqueue ();        Put the elements in Workqueue into a list and return} finally {Mainlock.unlock ();//unlock}//try terminating the thread pool tryterminate (); return to tasks; Return tasks not performed in Workqueue}

The general flow of Shutdownnow () and shutdown () is similar, with the difference being:

1. Update the thread pool to the stop state

2. Call interruptworkers () to interrupt all threads, including the running thread

3. Move the task to be processed in workqueue to a list and return at the end of the method, stating that Shutdownnow () will no longer handle tasks in Workqueue

Interruptworkers ()

private void Interruptworkers () {    final reentrantlock mainlock = This.mainlock;    Mainlock.lock ();    try {for        (Worker w:workers)            w.interruptifstarted ();    } finally {        mainlock.unlock ()}    }

Interruptworkers () is simply a loop that invokes interruptifstarted () on all workers, which determines whether the worker's Aqs state is greater than 0, that is, whether the worker has started to operate, Call Thread.Interrupt () again

It is important to note that calling Thread.Interrupt () on a running thread does not guarantee that the thread will be terminated, that Task.run () may have captured interruptexception inside, without throwing up, causing the thread to never end

Iii. awaittermination ()-Waiting for thread pool to terminate

Parameters:
Timeout: Timeout period
Unit:timeout Time-out units
Return:
True: Thread pool termination
False: exceeds timeout specified time
After a shutdown request is made, awaittermination () will be blocked until the following 3 scenarios occur
1. Complete execution of all tasks
2. Arrival time-out period
3. The current thread is interrupted

/** * Wait condition to support awaittermination */private final condition termination = mainlock.newcondition ();

The Awaittermination () loop determines whether the thread pool terminated terminated or has exceeded the time-out, and then waits for a period of time by termination this condition blocking

Termination.awaitnanos () is a blocking wait implemented through Locksupport.parknanos (this, nanostimeout)

The following specific situations occur during a blocking wait to unblock (an explanation of the above 3 cases):

1, if Termination.signalall () (internal implementation is Locksupport.unpark ()) will wake up the blocking wait, and because Threadpoolexecutor only in tryterminated () The attempt to terminate the thread pool succeeds and the thread pool is updated to the terminated state before it Signalall (), so Awaittermination () again determines that the state will return true to exit

2, if the timeout is reached Termination.awaitnanos () will also return, at this time nano==0, again cycle to determine return false, waiting for the thread pool to terminate the failure

3. If the current thread is Thread.Interrupt (), Termination.awaitnanos () will throw Interruptexception,awaittermination () to the calling thread, is unblocked in the form of an exception

therefore terminating the thread pool and needing to know whether it terminates can be used in the following ways:

Executorservice.shutdown (); try{while    (!executorservice.awaittermination (timeunit.milliseconds)) {        Logger.debug ("Waiting for Terminate");}    } catch (Interruptedexception e) {    //Interrupt processing}

Resources:

Deep understanding of the Java thread pool-threadpoolexecutor

Java thread pool Threadpoolexecutor usage and Analysis (iii)-Termination thread pool principle

Related Article

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.