See the thread pool provided by the JDK from the source (threadpoolexecutor)

Source: Internet
Author: User
Tags throwable

What is a thread pool

(1) When the blogger hears the thread pool three words the first idea is the database connection pool, recall, we are learning javaweb how to understand the database connection pool, the database to create the connection and close the connection is a more resource-intensive thing, for those many and short-lived tasks, will lead to frequent access and release of the connection, so that the efficiency of processing transactions is greatly reduced, so that we create a connection pool, which puts a specified number of connections, when the application needs a database connection to go inside to obtain, after use, and then put in the connection pool, so as to avoid the duplication of access and release connections, As to what kind of connection pool to get, we can decide according to the characteristics of the application and set parameters.
(2) The thread pool and connection pool are similar, and the thread pool is created to avoid duplicate thread creation and recycling. In the belief that existence is reasonable and there is merit (this argument is not universally applicable), the thread pool has the following three advantages:

① reduce resource consumption. Reduce the consumption caused by thread creation, destroying threads 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.
③ increases the manageability of threads. Threads are scarce resources, and if they are created, they will not only consume system resources, but also reduce the stability of the system, using a thread pool for uniform allocation, tuning, and monitoring.

Second, the use of Threadpoolexecutor

Threadpoolexecutor is the core class of the thread pool, so to understand thread pooling let's look at the implementation of the Threadpoolexecutor class first.
In the first learning to drive the concept of car repair, we first through the example to learn about the use of Threadpoolexecutor (later on the JDK source framework learning will be based on this principle).

public class Threadpoolexecutortest {public static void main (string[] args) {threadpoolexecutortest task = new        Threadpoolexecutortest (); Corepoolsize, Maximumpoolsize, KeepAliveTime, Unit, workQueue threadpoolexecutor threadPool = new Threadpoolexecu        Tor (5, +, Timeunit.milliseconds, new arrayblockingqueue<runnable> (4));        for (int i=0;i < 15;i++) {Threadpool.execute (task.new mytask (i));        } threadpool.shutdown ();    System.out.println ("End");        } public class MyTask implements Runnable {private int taskno;        Public mytask (int taskno) {this.taskno = TaskNo;            public void Run () {System.out.println ("task:" +taskno+ "executing");            try {thread.currentthread (). Sleep (4000);            } catch (Interruptedexception e) {e.printstacktrace ();        } System.out.println ("Task:" +taskno+ "execution End"); }    }}

Output:

任务:3正在执行任务:10正在执行任务:1正在执行任务:9正在执行任务:0正在执行任务:4正在执行任务:2正在执行任务:11正在执行任务:13正在执行任务:12正在执行任务:14正在执行end任务:1执行执行结束任务:5正在执行任务:9执行执行结束任务:6正在执行任务:11执行执行结束任务:7正在执行任务:3执行执行结束任务:8正在执行任务:10执行执行结束任务:12执行执行结束任务:2执行执行结束任务:13执行执行结束任务:14执行执行结束任务:0执行执行结束任务:4执行执行结束任务:6执行执行结束任务:5执行执行结束任务:8执行执行结束任务:7执行执行结束

The above example is threadpoolexecutor simple application, first need to create a task class MyTask, followed by the main method to create the Threadpoolexecutor object, and then use a for loop to simulate running multiple threads, and then execute method execution , and the last call to the shutdown method ends.
The implementation of the above code and our usual implementation of multithreading some differences, we always use:

Thread threadA = new Thread();thread.start();

To create a thread to perform a task, when applying threadpoolexecutor, we no longer create it ourselves, but instead use threads created by the thread pool for us.

When creating a thread pool Threadpoolexecutor object, there are a number of construction parameters, which we can learn by commenting that these parameters are used to set the characteristics of the thread pool.

Three, from the source view Threadpoolexecutor

1) threadpoolexecutor structure:

public class ThreadPoolExecutor extends AbstractExecutorService {    ...}public abstract class AbstractExecutorService implements ExecutorService {    ...}public interface ExecutorService extends Executor{    ...}public interface Executor {    ...}//ForkJoinPool 也继承自AbstractExecutorService public class ForkJoinPool extends AbstractExecutorService {    ...}

2) thread pool process at task:
Know the inheritance of threadpoolexecutor after we come to understand the threadpoolexecutor design structure and ideas, which we understand behind the Threadpoolexecutor source has a lot of help:

(The judgment on the queue should be within the online pool)

This diagram above should be able to describe the implementation of Threadpoolexecutor, but also to understand the threadpoolexecutor of the construction parameters.

When the thread pool is created, several important parameters, such as Corepoolsize,maximumpoolsize,workqueue, are set, corepoolsize refers to the size of the core thread pool, and maximumpoolsize refers to the maximum number of threads in the thread pool A workqueue the blocking queue specified for the thread pool.
Processing Flow:

    1. The main thread executes the Execute method, submits the task to the thread pool, and the thread pool determines whether the threads in the core thread pools are working, and if not, creates a thread to perform the new task, and if all is working, go to the next step.
    2. Determines whether the work queue is full, and if not, adds a new task to the blocking queue if it is full and enters the next step.
    3. Determines whether the thread pool threads are less than maximumpoolsize, and if less, creates a new thread to handle the new task, otherwise gives the saturation policy.

3) Source code:
Next we follow the implementation process of the method to follow the source code:
Where does the source code start with? Of course, from the start of the Execute method, after all, this is the beginning of the implementation of AH (Bo Master and the source or like this, so slowly follow, do not like to look directly at the construction, fields, methods, and so see the field properties and then go to see).

3.1 Execute:

public void Execute (Runnable command) {//To determine task validity if (command = = null) throw new NULLPOINTEREXCEP        tion ();        The CTL is a Atomicinteger type data//private final Atomicinteger ctl =//new Atomicinteger (Ctlof (RUNNING, 0));        The Ctlof method below is the value represented by runing and 0 or operation//private static int Ctlof (int rs, int wc)//{return rs | wc;}        private static final int RUNNING =-1 << count_bits;        Count_bits = integer.size-3;        So this c is the handle to the running value, the amount, the fuss ... int c = Ctl.get ();            If the number of threads running is less than corepoolsize if (Workercountof (c) < corepoolsize) {//If the line Cheng creates or assigns a new thread to the command task The Addworker method Boolean parameter is used to determine if the core pool is added to the task if (Addworker (command, True))//Exit program Retur            N        Update runing value c = ctl.get ();        }//private static Boolean isrunning (int c)//{return C < SHUTDOWN;} A shutdown value of 0, if less than this value, indicates that the run stop//offer is used to determine whether the task succeededQueue if (isrunning (c) && workqueue.offer (command)) {//get running value again int recheck = CTL.G            ET (); If the command is in the task queue, the Remove method removes the IF (! isrunning (recheck) && remove command)//command task            Given to the Saturation strategy reject (command);                 If the program is stopped by the shutdown or Shutdownnow method,//Then the wireless run is detected, do not add task to process else if (workercountof (recheck) = = 0)        Addworker (null, FALSE);    }//If the queue fails, then give the saturation policy else if (!addworker (command, False)) reject (command); }

I believe this method has not let me do more to repeat it (cover your mouth and laugh. jpg).
Here, let's make a list of some of the Threadpoolexecutor's fields:

private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));    private static final int COUNT_BITS = Integer.SIZE - 3;    private static final int CAPACITY   = (1 << COUNT_BITS) - 1;    // runState is stored in the high-order bits    private static final int RUNNING    = -1 << COUNT_BITS;    private static final int SHUTDOWN   =  0 << COUNT_BITS;    private static final int STOP       =  1 << COUNT_BITS;    private static final int TIDYING    =  2 << COUNT_BITS;    private static final int TERMINATED =  3 << COUNT_BITS;    // 这几个方法我也将它们看做字段了    private static int runStateOf(int c)     { return c & ~CAPACITY; }    private static int workerCountOf(int c)  { return c & CAPACITY; }    private static int ctlOf(int rs, int wc) { return rs | wc; }    //总之,为了效率,源码的位运算常见的跟喝茶似的

If there is no reference to the source of the blog's small partners may have a lot of questions, I believe you open the source code and look at my method comments will be better understand!

3.2 Addworker:
Looking at the Execute method above, I believe we can see that the Addworker method is also the core, and the Addworker method serves as all the operations that give the task to the thread:

   Addworker method Two parameters, the first parameter needless to say, the second one before we said//it is used to differentiate where the task is to be delivered (whether it is the core thread pool) Private Boolean addworker (Runnable firsttask, BOOL EAN core) {/* Description: In fact, retry is a marker, marking the time when the program jumps out of the loop, where to start, * functions similar to goto. Retry is usually followed by a For loop, the first retry the following * line is the For loop, and the second retry is generally continue or break. */retry:for (;;)            {//get running int c = Ctl.get ();            Operating state 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);                    The following can be seen by the Boolean type parameter core action 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}}//There is a question here, if the above has been a dead loop, even if the break out of the loop, then according to the//retry feature, will not be the execution of the dead loop, and then reciprocating loop? Oh, you know, when the above conditions are not met//no need to execute the above code, this ...        The thinking is rigid ... boolean workerstarted = false;                Boolean workeradded = false;        Worker w = null;            try {//From here we can see the wrapper for the thread w = new Worker (firsttask);            This creates the thread final threads t = w.thread;                Validity judgment if (t! = null) {//Here to lock the 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 for HashSet//is used to store the wrapped worker thread Workers.add (w);                        int s = workers.size ();                        if (S > largestpoolsize) largestpoolsize = s;                    Workeradded = true;                }} finally {Mainlock.unlock ();                    }//When added successfully, the if (workeradded) {T.start () will be activated;                Workerstarted = true;        }}} finally {if (! workerstarted) addworkerfailed (w);    } return workerstarted; }

From the above code we can find that when the task is given to the thread execution is not directly to the thread, the thread pool after creating the thread will be wrapped into a worker thread worker,worker after the work will continue to the work queue to get the task to execute.

3.3 Worker class:

 private final class Worker        extends AbstractQueuedSynchronizer        implements Runnable{    ...}

We can get a glimpse of this from the run method of the worker class below:
jdk1.8 and 1.7 have a lot of changes, interested friends can go to compare

 public void run() {            runWorker(this);        }
   final void Runworker (Worker w) {Thread wt = Thread.CurrentThread ();        Runnable task = W.firsttask;        W.firsttask = null; W.unlock ();        Allow interrupts Boolean completedabruptly = true;  try {//The following line is the focus//task not empty or gettask (Get queue Task) is not empty when//the task is locked for processing 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 {//Run task.run here ();                    } 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); }    }

3.4 Submit:
Since we talked about the Execute method, how can we reduce the submit method, when we perform a task, sometimes we need to return the value, this time we need to use the Submit method.
In fact, we can find through the source of the Submit method is also called the Execute method, when the Submit method is called we can receive a future object, we can call the future object's Get method to get its return value.
For future knowledge, you can refer to:
Https://www.cnblogs.com/cz123/p/7693064.html
Note: I found the Submit method in Threadpoolexecutor, and then found that Threadpoolexecutor was directly inheriting his father Abstractexecutorservice.

 public Future<?> submit(Runnable task) {        //验证任务有效性        if (task == null) throw new NullPointerException();                RunnableFuture<Void> ftask = newTaskFor(task, null);        execute(ftask);        return ftask;    }

From the code above we can see that the task is wrapped into a Runnablefuture object, and then the object is executed with execute.
If you look at the posts I recommended above, readers should know the difference between callable and runnable: whether there is a return value.

Let's take a look at the structure of the future:
futuretask→ (Implementation) runnablefuture→ (inheritance) runnable,future

We can look at the Newtaskfor method:

 protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {        return new FutureTask<T>(runnable, value);    }

Its bottom layer is actually a new Futuretask object, so Futuretask is the real implementation class Oh!
On the implementation of Futuretask, we will devote time to organize!

3.5shutdown and Shutdownnow:
We can close the thread pool through the shutdown and Shutdownnow methods, the shutdown method by traversing the worker thread HashSet, setting the Run state (CTL) this to shutdown and calling the interrupt method to break all threads, Shutdownnow also traverses all threads, sets the Run state (CTL) to stop, and calls the interrupt method to break all threads.

  public void shutdown () {//need to lock interrupt final reentrantlock mainlock = This.mainlock;        Mainlock.lock ();            try {//Guaranteed thread can interrupt checkshutdownaccess ();            Change the operating state, the underlying is atomic operation Advancerunstate (SHUTDOWN);            This method iterates over the global variable Workers (HASHSET)//calls the Interrupt Method Interruptidleworkers () on all worker threads in this.            An empty method//This is what the official said://used by Scheduledthreadpoolexecutor//to Cancel delayed tasks. OnShutdown ();        Hook for Scheduledthreadpoolexecutor} finally {Mainlock.unlock ();    } tryterminate (); }
public List<Runnable> shutdownNow() {        List<Runnable> tasks;        final ReentrantLock mainLock = this.mainLock;        mainLock.lock();        try {            //保证线程可中断            checkShutdownAccess();            //ctl设置为STOP            advanceRunState(STOP);            interruptWorkers();            //这个就是两个方法区别            //这个方法将工作队列中的任务(还未执行)            //取出放到list中            tasks = drainQueue();        } finally {            mainLock.unlock();        }        tryTerminate();        return tasks;    }

3.6 Rejectedexecutionhandler:
Finally we look at this saturation strategy, when the thread and queue are full, indicating that the thread pool is saturated, then we have to take some action to handle these tasks, and by default we will execute AbortPolicy, indicating that we cannot handle the task and throw an exception.
At the same time, the JDK provides several strategies:

    • AbortPolicy: Throwing Exceptions directly
    • Callerrunspolicy: Executing a task with the caller's thread
    • Discardoldestpolicy: Discard the most recent task in the queue and perform this task
    • Discardpolicy: Discard, do not process

We can also implement the Rejectedexecutionhandler interface for custom operations, such as sometimes we need to record this exception in the log, this time we need to customize!

Summary: Through the thread pool of learning, and I know many of their own knowledge, such as the future interface, but also through learning, found some containers and locks really very common, their usual application when rarely encountered, of course, the master of the programming level is also worthy of our Wang study!

See the thread pool provided by the JDK from the source (threadpoolexecutor)

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.