Java thread Pool---threadpoolexecutor source analysis __java

Source: Internet
Author: User
Tags throw exception volatile

In multithreaded programming, more or less have heard or used the thread pool, the rational use of thread pool can bring three benefits. Reduce resource consumption. Reduces the consumption caused by thread creation and destruction by reusing threads that have already been created. Improve response speed. When a task arrives, the task can be executed immediately without waiting for the thread to be created. Improve the manageability of threads. Thread is a scarce resource, if unlimited creation, will not only consume system resources, but also reduce the stability of the system, the use of thread pool can be unified allocation, tuning and monitoring.

But to do a reasonable use of the thread pool, it must be more understanding of its principles, today we come to a brief analysis of the implementation of the thread pool-the source is not the secret thread pool infrastructure (JDK 1.8)

In order to better understand the thread pool, or to first comb its architecture, help our analysis, otherwise very confusing. Inheritance System

Executor

Executor, the task executor, almost all classes in the thread pool framework implement the Executor interface directly or indirectly, which is the basis of the thread pool framework. It separates the submission of the task from the execution of the task (producer-consumer mode), which provides only one execute () method to perform the runnable task that has been committed.

/**
 * Executes the given command at some time in the future.  The command
 * May execute in a new thread, in a pooled thread, or
 in the calling * thread, at the discretion of th e {@code Executor} implementation.
 *
 @param command the runnable task
 * @throws Rejectedexecutionexception If this task cannot is
 * accepted fo R execution
 * @throws nullpointerexception if command is null
/void Execute (Runnable command);
Excutorservice

Excutorservice is also an interface that inherits the executor interface, and by name we know that it provides a service, Executorservice provides the interface (Submit method) that delivers the task to the performer, and lets the performer perform the task (InvokeAll , Invokeany method) interface, and so on.

Public interface Executorservice extends Executor {/** * Close the thread pool, tasks that have been committed are executed, but new tasks are not accepted * This method does not wait for a committed task to finish executing

    * * void shutdown ();
     /** * Trying to stop all active tasks, pausing pending tasks * Returns the list of tasks waiting to be executed * This method does not wait for the task being executed to terminate.

    * * list<runnable> shutdownnow ();
     /** * Returns True if the executor is closed.

    * * Boolean isshutdown (); /** * Returns True if all tasks have been completed after shutdown * Note: Only shutdown or shutdownnow are invoked before isterminated can return True/Boolean istermin

    Ated ();
    /** * Shutdown request, or the timeout occurs, or the current thread is * interrupted, will cause blocking until all tasks are executed.

    Boolean awaittermination (long timeout, timeunit unit) throws Interruptedexception;

    /** * Submit task for execution, return Future, can obtain task execution results via Future/<T> future<t> Submit (callable<t> Task); /** * Commits a Runnable task for execution, and returns a Future * * <T> future<t> submission that represents the task (Runnable task, T result

    ); /** * Submit a Runnable task for execution, andReturns a Future/future<?> submit (Runnable Task) that represents the task; /** * Performs the given task, and returns a Future list of the status and results of the task when all tasks are complete/<T> list<future<t>> InvokeAll (collection& lt;?

    Extends callable<t>> tasks) throws interruptedexception; /** * Performs a given task, returning a Future list that maintains the status and results of the task when all tasks are completed or expired (whichever occurs first) * * <T> list<future<t>> Invoke
        All (collection&lt. extends callable<t>> tasks, long timeout, timeunit unit)

    Throws Interruptedexception; /** * Performs the given task, if a task has completed successfully (that is, no exception is thrown), returns its result/<T> T invokeany (collection<? extends Callable<t&gt

    ;> tasks) throws Interruptedexception, executionexception; /** * Performs a given task, and returns its result if a task completes successfully (that is, no exception is thrown) before the given time-out expires/<T> T invokeany (collection<? extends Callabl e<t>> tasks, long timeout, timeunit unit) throws Interruptedexception, ExecutionException, TimeoutException; }

The source code has a very full annotation, can be very good to help understand. Abstractexecutorservice

Abstractexecutorservice abstract class, implements the Executorservice interface, provides the default implementation, and below is a look at a few of the methods we often use.

Protected <T> runnablefuture<t> newtaskfor (callable<t> callable) {return
    new futuretask<t > (callable);
}
Protected <T> runnablefuture<t> newtaskfor (Runnable Runnable, T value) {return
    new futuretask<t> (runnable, value);
}

The callable object wrapped into Futuretask object, in the previous article, we analyzed the futuretask, so here is not analyzed, you can refer to: Java multithreading-futuretask Source Analysis

Submit Runnable Task Public
future<?> Submit (Runnable Task) {
    if (task = null) throw new NullPointerException () ;
    runnablefuture<void> ftask = newtaskfor (task, null);
    Execute, the Execute method is given to a specific subclass to implement
    execute (ftask);
    return ftask;
}

Submit Runnable tasks and specify results public
<T> future<t> Submit (Runnable tasks, T result) {
    if (task = null) throw New NullPointerException ();
    runnablefuture<t> ftask = newtaskfor (task, result);
    Execute (ftask);
    return ftask;
}

Submit callable Task Public
<T> future<t> submit (callable<t> Task) {
    if (task = null) throw new Nu Llpointerexception ();
    runnablefuture<t> ftask = newtaskfor (Task);
    Execute (ftask);
    return ftask;
}

The approximate process is to encapsulate the submitted task into a Futuretask object and then execute the task, which is implemented by the specific subclass. Threadpoolexecutor

We will introduce Scheduledthreadpoolexecutor in detail later.

Scheduledthreadpoolexecutor inherits Threadpoolexecutor to reuse the thread pool functionality, scheduledthreadpoolexecutor to support the scheduling of recurring tasks, which we analyze later. Threadpoolexecutor

Java thread pool support mainly through the threadpoolexecutor to implement, we use the executorservice of the various thread pool strategy is based on threadpoolexecutor to achieve, So threadpoolexecutor is very important to understand the various thread pool strategy, must first understand threadpoolexecutor. Data Structure

/** * The control state of the entire thread pool, which contains two properties: the number of valid threads, the state of the thread pool (runstate).  * Workercount, number of valid threads (low 29 bits) * runstate, thread pool status (high 3 bits) * CTL contains 32-bit data, low 29-bit number of stored threads, high 3-bit deposit Runstate,runstate 5 values: * RUNNING: Accept new tasks, work with tasks in queue * SHUTDOWN: Do not accept new tasks, work with tasks in queue * STOP: New tasks are not accepted, tasks in the task queue are not processed * Tidying: All tasks are completed, the number of threads is 0, and then execution terminate D () * terminated:terminated () has completed * State transition: * RUNNING-> SHUTDOWN: Invoke SHUTDOWN () method * (RUNNING or SHUTDOWN)-> S  Top: Called Shutdownnow () method * SHUTDOWN-> tidying: There is no task in the queue, and the thread pool has no threads. * STOP-> tidying: Thread pool has no threads * Tidying->
 Terminated:terminated () method call Complete * * Private final Atomicinteger ctl = new Atomicinteger (Ctlof (RUNNING, 0));
 29-bit offset private static final int count_bits = integer.size-3;
 Maximum Capacity (2^29-1) private static final int CAPACITY = (1 << count_bits)-1;
 Blocking queues (Task queues) private final blockingqueue<runnable> workqueue;
 Convertible lock Private final reentrantlock Mainlock = new Reentrantlock (); Worker threads Collection private final hashset<worker> Workers = new hashset<worker> ();
 Termination conditions Private final Condition termination = Mainlock.newcondition ();
 Thread pool maximum capacity private int largestpoolsize;
 Number of tasks completed private long completedtaskcount;
 Thread factory (generating thread) private volatile threadfactory threadfactory;
 Thread pool reject task policy private volatile Rejectedexecutionhandler handler;
 When the thread pool is idle, the threads live at a time private volatile long keepalivetime;
 Whether to run the core line blocks until those private volatile Boolean allowcorethreadtimeout;
 Core thread pool size private volatile int corepoolsize;
 Max thread pool size private volatile int maximumpoolsize;
 Get thread pool status private static int runstateof (int c) {return C & ~capacity;}
 Gets the number of worker threads private static int workercountof (int c) {return C & CAPACITY;} Get CTL private static int Ctlof (int rs, int wc) {return rs | wc;}
CTL Properties

State variable CTL: Contains two attributes: number of valid threads (workercount: Low 29-bit), Thread pool state (runstate: High 3 bits).
Runstate has 5 values: RUNNING: Accept new tasks, work with tasks in queue SHUTDOWN: Do not accept new tasks, work on tasks in queue STOP: New tasks are not accepted, tasks in the task queue are not processed tidying: All tasks are completed, threads are 0, Then execute terminated () terminated:terminated () is completed

State transitions:
RUNNING-> SHUTDOWN: Calling the SHUTDOWN () method
(RUNNING or SHUTDOWN)-> STOP: Called Shutdownnow () method
SHUTDOWN-> Tidying: There is no task in the queue, and the thread pool has no threads.
STOP-> tidying: Thread pool has no threads
Tidying-> terminated:terminated () method call complete corepoolsize

The number of core threads in the thread pool. When a task is committed, the thread pool creates a new thread to perform the task until the current number of threads equals Corepoolsize. If the Prestartallcorethreads () method of the thread pool is invoked, the thread pool creates and starts all the base threads in advance. maximumpoolsize

The maximum number of threads allowed in the thread pool. After the thread pool's blocked queue is full, if a task is committed, a new thread is created to perform the task if the current number of threads is less than maximumpoolsize. Note that if you are using a unbounded queue, this parameter will have little effect. KeepAliveTime

The time that the thread is idle. The creation and destruction of threads is a price to pay. The thread does not destroy immediately after performing the task, but continues to live for some time: KeepAliveTime. By default, this parameter takes effect only if the thread count is greater than corepoolsize. Workqueue

A blocking queue that is used to hold tasks waiting to be performed, and the waiting task must implement the Runnable interface. Rejectedexecutionhandler

Rejectedexecutionhandler, the thread pool's rejection policy. A rejection policy is when a task is added to a thread pool, and the thread pool rejects the appropriate policy for that task. When a task is submitted to a thread pool, if the thread in the thread pool is already saturated and the blocking queue is full, the thread pool chooses a deny policy to handle the task.

The thread pool provides four kinds of rejection policies:
1. AbortPolicy: Direct throw exception, default policy;
2. Callerrunspolicy: Execute the task with the thread of the caller;
3. Discardoldestpolicy: Discard the top task in the blocking queue and perform the current task;
4. Discardpolicy: direct discard task;

Of course, we can also implement their own rejection strategy, the implementation of Rejectedexecutionhandler interface can be. thread pool processing process

The thread pool processing process is as follows (from the Art of Java Concurrent programming):

Threadpoolexecutor Execute Execute method is divided into the following 4 kinds

1. If the currently running thread is less than corepoolsize, a new thread is created to perform the task (the task does not need to be in the blocking queue).
2. If the thread that is running is greater than or equal to Corepoolsize, join the task to Blockingqueue.
3. If you cannot join Blockingqueue (the queue is full), create a thread to perform the task if the number of threads is less than maxpoolsize.
4. If the number of threads is greater than or equal to maxpoolsize, then the Reject policy is executed.

Construction Method

The creation of a thread pool can be achieved through the Threadpoolexecutor construction method:

Public threadpoolexecutor (int corepoolsize,
                          int maximumpoolsize,
                          long KeepAliveTime,
                          timeunit Unit,
                          blockingqueue<runnable> Workqueue,
                          Threadfactory threadfactory,
                          Rejectedexecutionhandler handler) {
    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 various meanings of the parameters have been analyzed above. submitting tasks to the thread pool

You can use two methods to submit a task to the thread pool, execute (), and the Submit () method.
The Execute () method is used to commit a task that does not need to return a value, so it is not possible to determine whether the task was successfully executed by the thread pool.
The Submit () method is used to submit a task that needs to return a value. The thread pool returns an object of type future, through which the future object can determine whether the task was executed successfully, and can obtain the return value through Future's Get () method, which blocks the current thread from knowing that the task is complete, and uses the fetch (long timeout, Timeunit unit) method blocks the current thread from returning immediately after a period of time, and it is possible that the task has not been completed. Submit

The Submit method we have analyzed in the abstractexecutorservice, we can refer to the previous Abstractexecutorservice analysis. Execute

/** 1.  Executes the given task sometime in the future. The Task 2.
 May execute in a new thread or in a existing pooled thread. 3. If the task cannot be submitted to execution, either because this 4. has been shutdown or because its capacity has executor been, 5.
 The task is handled by the current {@code Rejectedexecutionhandler}.
    */public void execute (Runnable command) {if (command = = null) throw new NullPointerException (); * * Proceed in 3 steps: * 1. If the running thread is less than corepoolsize, an attempt is made to create a new thread to perform the task, * calling the Addworker function atomically checks runstate and workcount to ensure the correct add thread * 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 I prevents false alarms that would add
     * Threads when it shouldn ' t, by returning false. * 2. If a task succeeds in queuing, a double check is still required when adding a thread (because the thread died after the previous check), * or when entering this method, the thread pool has shutdoWN, so you need to check the status again, and if necessary, roll back into the queue operation when you stop, * or create a new thread when the thread pool has no threads * 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 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. * *3. If the queue cannot be queued, an attempt is made to add a new thread, if the operation fails, * then it means that the thread pool is shutdown or saturated, so reject task * 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.
    *//Get state variable int c = Ctl.get (); Gets the current number of valid threads through the Workercountof method, or if less than corepoolsize, attempts to create a thread to perform the task if (Workercountof (c) < corepoolsize) {//Create a work thread
        Perform a task if (Addworker (command, True)) return;
    c = Ctl.get (); }//thread pool is in running state attempts to join task queue if (isrunning C&& workqueue.offer (command)) {//re-check int recheck = Ctl.get (); The thread pool is not in the running state, the task is removed from the task queue if (! isrunning (Recheck) && remove (command) reject (command); Execute a deny policy else if (workercountof (recheck) = = 0)/thread pool is in shutdown state, there is no active thread, but there are tasks in the queue that do not perform this special case, you may need to add work
    Thread to perform the task Addworker (null, FALSE); else if (!addworker (command, FALSE))//Then try to create a new thread to perform the task reject (command); Failed, execution reject policy (number of valid threads >=maximumpoolsize)}

The implementation process is generally as follows:

If the thread pool has a valid number of threads less than corepoolsize, then call Addworker create a new thread to perform the task, return true successfully, and fail to perform step 2.

If the thread pool is in the running state, try to join the task in the queue queue, and if the join queue succeeds, try double Check and, if the join fails, proceed to step 3. If the thread pool is not a running state or if the join queue fails, the attempt is made to create a new thread until a valid thread reaches Maxpoolsize, and if it fails, The Reject () method is invoked to execute the reject policy.

The primary purpose of Double Check is to determine whether a thread added to the queue queue can be executed. If the thread pool is not a running state, call the Remove () method to remove the task from the blocking queue and then call The Reject () method to process the task.
Worker

In the front, we mentioned many times the work thread, now we have to uncover its veil, the worker is the real task, is completed by the task execution thread. Each Worker object contains a new task that needs to be executed immediately and the number of tasks that have been performed, and the worker itself is a Runnable object that inherits Abstractqueuedsynchronizer, so that the worker itself is also a synchronization component.
Property

//worker hold threads final thread thread;/** Initial task to run. possibly null.
* *//specific task Runnable firsttask;
/** Per-thread Task Counter * * volatile long completedtasks; Worker (Runnable firsttask) {//Init sync State, in this state, can not be interrupted, see interruptifstarted () method SetState ( -1);//Inhibit interrupts U
    Ntil Runworker this.firsttask = firsttask;
Create Thread this.thread = Getthreadfactory (). Newthread (this); /** delegates main run loop to outer runworker */public void Run () {//Delegate to Runworker Runworker (this);} void in
    Terruptifstarted () {Thread T; if (getState () >= 0 && (t = thread)!= null &&!t.isinterrupted ()) {try {T.interr
        UpT (); The catch (SecurityException ignore) {}}} ...//omit partial method 

The

internally encapsulates a thread object that executes its own run method, and the thread object creates a new thread from the Threadfactory object provided by Threadpoolexecutor. (the benefit of separating worker and thread is that if our business code requires other controls, such as priority, thread name, thread execution strategy, and so on, for threads in the thread pool, you can extend your own threadfactory. No need to inherit or overwrite Threadpoolexecutor) Addworker

Private Boolean Addworker (Runnable Firsttask, Boolean core) {retry:for (;;)
         {int c = ctl.get ();

         Thread pool state int rs = runstateof (c);
             /** * If the thread pool is SHUTDOWN, you need to determine if there are tasks in the task queue, and if so, you will need to perform the */if (Rs >= SHUTDOWN && !
             (rs = = SHUTDOWN && Firsttask = = null &&! workqueue.isempty ()))

         return false; for (;;)
             {//number of active worker threads int WC = Workercountof (c);
                 Worker number is greater than or equal to maximum capacity if (WC >= CAPACITY | |  The number of worker is greater than or equal to the core thread pool size or max thread pool size WC >= (core corepoolsize:maximumpoolsize) return
             False
             Increase the number of worker if (Compareandincrementworkercount (c)) break retry;  state variable c = ctl.get ();
     Re-read CTL//This state is not the same as the last obtained state if (runstateof (c)!= RS)            Continue retry; Else CAS failed due to workercount;
     Retry Inner Loop}} Boolean workerstarted = false;
     Boolean workeradded = false;
     Worker w = null;
         try {//encapsulate the task in worker w = new Worker (Firsttask);
         Final Thread t = w.thread;
             if (t!= null) {final Reentrantlock mainlock = This.mainlock;
             Lock Mainlock.lock ();
                 try {//recheck while holding lock.
                 Threadfactory failure or if//Shut down before lock acquired.
                 Thread pool state int rs = runstateof (Ctl.get ()); 
                     If the thread pool is in the running state to perform the Add task operation, or the thread pool is SHUTDOWN, the Firsttask is empty (the task queue is not empty and a worker thread needs to be added to perform the task) if (Rs < SHUTDOWN | | (rs = = SHUTDOWN && firsttask = null))
           {if (t.isalive ())//PreCheck that T-startable              throw new Illegalthreadstateexception ();
                     Add a worker to the Worker Collection Workers.add (w);
                     int s = workers.size ();
                     if (S > largestpoolsize) largestpoolsize = s;
                 Workeradded = true;
             finally {//release lock Mainlock.unlock ();
                 } if (workeradded) {//Start thread, perform task T.start ();
             Workerstarted = true;
     }} finally {//worker thread creation failure if (! workerstarted) addworkerfailed (w);
 return workerstarted; }

Addworker The general process is as follows: To determine the thread pool state, if you need to create a worker thread, the increase of atomicity workercount. Encapsulates a task as a worker and adds this worker to the workers collection. Start the worker's corresponding thread and start the thread to run the worker's Run method. If the rollback worker's creation action (addworkerfailed method) fails, the worker is removed from the workers collection and the atomic reduction is workercount. Runworker

final void Runworker (Worker w) {
    Thread wt = Thread.CurrentThread ();
    Runnable task = W.firsttask;
    W.firsttask = null;
    Release Lock (set state to 0, allow interrupt)
    w.unlock ();//Allow interrupts
    boolean completedabruptly = true;
    try {
        //task is not null or blocking queue still exists task
        

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.