Java Multithreading Series--"Juc thread pool" 02 Thread pool principle (i)
Threadpoolexecutor Introduction
Threadpoolexecutor is a thread pool class. For the thread pool, it can be popularly understood as "a collection of threads that hold a certain number of threads." The thread pool allows the number of threads that are allowed to run concurrently, which is the capacity of the thread pool, and some threads block waiting when the thread that is added to the thread pools exceeds its capacity. The thread pool manages the threads that are added to the thread pool through the appropriate scheduling policies and deny policies. "
threadpoolexecutor Data Structure
The data structure of the Threadpoolexecutor is as follows:
The individual data is defined in Threadpoolexecutor.java as follows:
Blocks the queue. Private final blockingqueue<runnable> workqueue;//mutex private final reentrantlock Mainlock = new Reentrantlock (); /thread collection. A worker corresponds to a thread. Private final hashset<worker> workers = new hashset<worker> ();//"Termination condition", bound to "Mainlock". Private final Condition termination = Mainlock.newcondition ();//The maximum number of thread pool threads ever reached. private int largestpoolsize;//The number of completed tasks private long completedtaskcount;//Threadfactory object that is used to create the thread. Private volatile threadfactory handles the threadfactory;//rejection policy. Private volatile Rejectedexecutionhandler handler;//keeps the thread alive for a long time. Private volatile long keepalivetime;private volatile Boolean allowcorethreadtimeout;//core pool size private volatile int corepoolsize;//Max pool Size private volatile int maximumpoolsize;
1. Workers
Workers is a hashset<work> type, that is, it is a worker collection. A worker corresponds to a thread, which means that the thread pool contains a "collection of threads" through workers. When the worker's thread pool is started, it executes the task in the thread pool, and when a task is completed, it takes a blocked task out of the blocking queue of the thread-pool to continue running.
The role of wokers is that the thread pool implements the "Allow multiple threads to run simultaneously" through it.
2. WorkQueue
Workqueue is a blockingqueue type, that is, it is a blocking queue. When the number of threads in the thread pool exceeds its capacity, the thread enters the blocking queue for blocking waits.
Through Workqueue, the thread pool implements the blocking function.
3. Mainlock
Mainlock is a mutex that enables mutually exclusive access to the thread pool through Mainlock.
4. Corepoolsize and Maximumpoolsize
Corepoolsize is the core pool size, and maximumpoolsize is the maximum pool size. Their role is to adjust the number of threads actually running in the thread pool.
For example, when a new task is submitted to the thread pool (via the Execute method).
--If at this point, the number of threads running in the thread pool < corepoolsize, a new thread is created to process the request.
--If at this point, the number of threads running in the thread pool > corepoolsize, but < maximumpoolsize, the new thread is created only when the blocking queue is full.
If you set the same corepoolsize and Maximumpoolsize, a fixed-size thread pool is created. If you set Maximumpoolsize to a basic unbounded value (such as Integer.max_value), the pool is allowed to accommodate any number of concurrent tasks. In most cases, values for the core pool size and the maximum pool size are set at the creation thread pool, but dynamic changes can also be made using setcorepoolsize (int) and setmaximumpoolsize (int).
5. Poolsize
Poolsize is the actual size of the current thread pool, which is the number of tasks in the thread pools.
6. Allowcorethreadtimeout and KeepAliveTime
Allowcorethreadtimeout indicates whether the thread is allowed to survive idle, while KeepAliveTime is the idle thread is terminated when the thread pool is idle for more than KeepAliveTime time.
7. Threadfactory
Threadfactory is the Threadfactory object. It is a thread factory class that "thread pool creates threads through Threadfactory".
8. Handler
Handler is the Rejectedexecutionhandler type. It is a handle to the thread pool rejection policy, which means that when a task is added to the thread pool and the thread pools reject the task, the thread pool is handled appropriately by handler.
In summary, the thread pool manages the threads collection through workers, and each thread executes the task in the thread pool after it is started, and when a task finishes executing, it pulls the task out of the blocking queue of the thread pool to continue running. The blocking queue is the queue that manages the thread pool task, which enters the blocking queue to wait when the task that is added to the thread pools exceeds the capacity of the line pool.
thread pool Scheduling
We take a look at the following figure to see the scheduling strategy of the task in the thread pool below, and deepen our understanding of threads.
Figure -01:
Figure -02:
Description :
In Figure 01, there are n tasks in the thread pool. "Task 1", "Task 2", "Task 3" the 3 tasks are executing, while "Task 3" to "Task N" waits in the blocking queue. The task being performed, in the workers collection, the Workers collection contains 3 workers, each worker corresponds to a thread, and the thread thread processes one task at a time.
When a task is processed in the workers collection, a task is removed from the blocking queue to continue execution, as shown in 02. Figure 02 means that when task 1 is processed, the thread pool takes task 4 out of the blocking queue and places it in workers for processing.
Java Multithreading Series--"Juc thread pool" 03 thread pool principle (ii)
Line Pooling Example
Before analyzing the thread pool, look at a simple line pooling example.
1 Import java.util.concurrent.Executors; 2 Import Java.util.concurrent.ExecutorService; 3 4 public class ThreadPoolDemo1 {5 6 public static void Main (string[] args) {7 //Create a thread pool that can reuse a fixed number of threads 8
executorservice pool = Executors.newfixedthreadpool (2); 9 //Create implements the Runnable interface object, the thread object of course also implements the Runnable interface of ten thread ta = new MyThread (); one thread TB = new MyThread (); the thread TC = new MyThread (), the thread td = New MyThread (), and the thread te = new MyThread (); Line implementation of Pool.execute (TA), pool.execute (TB), Pool.execute (TC), Pool.execute (TD); 20 Pool.execute (TE); //Close thread pool pool.shutdown (); }24}25-class MyThread extends thread {27 28< c20/> @Override29 public void Run () { System.out.println (Thread.CurrentThread (). GetName () + "is running."); }32}
Operation result :
Pool-1-thread-1 is Running.pool-1-thread-2 is running.pool-1-thread-1 are Running.pool-1-thread-2 is Running.pool-1-thread-1 is running.
example, including the creation of a thread pool, adding a task to the thread pool, and shutting down the thread pools are 3 main steps. Later, we will analyze the threadpoolexecutor from these 3 aspects.
Line Cheng Code Analysis
(i) Creating the thread pool
The following Newfixedthreadpool () describes the thread pool creation process.
1. Newfixedthreadpool ()
Newfixedthreadpool () defined in Executors.java, the source code is as follows:
public static Executorservice newfixedthreadpool (int nthreads) { return new Threadpoolexecutor (Nthreads, Nthreads, 0L, Timeunit.milliseconds, new linkedblockingqueue<runnable> ());}
Description : The Role of newfixedthreadpool (int nthreads) is to create a thread pool, and the capacity of the thread pool is nthreads.
Newfixedthreadpool (), when calling Threadpoolexecutor (), passes a linkedblockingqueue () object, and Linkedblockingqueue is a blocking queue implemented by the one-way list. In a thread pool, this is the blocking queue that enables "some tasks to block waiting when the number of tasks in the threads pool exceeds the number of allowed tasks."
For details on the implementation of Linkedblockingqueue, readers can refer to the "Java Multithreaded Series-" Juc collection "08 Linkedblockingqueue".
2. Threadpoolexecutor ()
Threadpoolexecutor () defined in Threadpoolexecutor.java, the source code is as follows:
Public threadpoolexecutor (int corepoolsize, int maximumpoolsize, long KeepAliveTime, timeunit Unit, blockingqueue<runnable> WorkQueue) {This (corepoolsize, maximumpoolsize, KeepAliveTime, Unit, WorkQueue, executors.defaultthreadfactory (), DefaultHandler);}
Description : This function is actually another constructor that calls Threadpoolexecutor. The source code for this function is as follows:
public threadpoolexecutor (int corepoolsize, int maximumpoolsize, lo Ng 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 (); Core Pool Size this.corepoolsize = corepoolsize; Max Pool Size this.maximumpoolsize = maximumpoolsize; Waiting queue for thread pool This.workqueue = WorkQueue; This.keepalivetime = Unit.tonanos (KeepAliveTime); Thread Factory Object this.threadfactory = Threadfactory; Handle of the Deny policy This.handler = handler;}
description : In the constructor of Threadpoolexecutor (), the initialization work is performed.
Corepoolsize, maximumpoolsize, Unit, KeepAliveTime, and workqueue the values of these variables are known, and they are all passed through Newfixedthreadpool (). Here's a look at the Threadfactory and handler objects.
2.1 Threadfactory
The threadfactory in the thread pool is a thread factory, and thread pool creation threads are all done through thread factory objects (threadfactory).
The Threadfactory object referred to above is returned by Executors.defaultthreadfactory (). Executors.java in the defaultthreadfactory () source code is as follows:
public static Threadfactory Defaultthreadfactory () { return new defaultthreadfactory ();}
Defaultthreadfactory () returns the Defaultthreadfactory object. Executors.java in the defaultthreadfactory () source code is as follows:
Static Class Defaultthreadfactory implements Threadfactory {private static final Atomicinteger Poolnumber = new Atomic Integer (1); Private final Threadgroup Group; Private final Atomicinteger threadnumber = new Atomicinteger (1); Private final String Nameprefix; Defaultthreadfactory () {SecurityManager s = System.getsecuritymanager (); Group = (s! = null)? S.getthreadgroup (): Thread.CurrentThread (). Getthreadgroup (); Nameprefix = "pool-" + poolnumber.getandincrement () + "-thread-"; }//provides the API for creating threads. Public thread Newthread (Runnable r) {//thread corresponding task is Runnable object R thread t = new Thread (group, R, Nameprefix + threadnumber.getandincrement (), 0); Set to "Non-daemon Thread" if (T.isdaemon ()) T.setdaemon (false); Set priority to "Thread.norm_priority" if (t.getpriority ()! = thread.norm_priority) T.setpriority (thread.norm_priority); return t; }}
Description : The role of Threadfactory is to provide a thread factory that creates the functionality of the thread.
It is provided by Newthread () to provide the ability to create threads, the following is simply said Newthread (). Newthread () Creates a thread that corresponds to the Runnable object, which creates threads that are "non-daemon Threads" and "thread priority is thread.norm_priority".
2.2 Rejectedexecutionhandler
Handler is a handle to the deny policy in Threadpoolexecutor. The so-called deny policy, when you add a task to the thread pool, the thread pool rejects the corresponding policy that the task takes.
The thread pool defaults to the DefaultHandler policy, which is the AbortPolicy policy. In the AbortPolicy policy, the thread pool throws an exception when rejecting a task!
DefaultHandler is defined as follows:
private static final Rejectedexecutionhandler DefaultHandler = new AbortPolicy ();
The source code of AbortPolicy is as follows:
public static class AbortPolicy implements Rejectedexecutionhandler {public AbortPolicy () {} //throws an exception public void Rejectedexecution (Runnable R, Threadpoolexecutor e) { throw new rejectedexecutionexception ("Task" + r.to String () + "rejected from" + e.tostring ());} }
(ii) Adding tasks to the thread pool
1. Execute ()
Execute () is defined in Threadpoolexecutor.java and the source code is as follows:
public void Execute (Runnable command) {//If the task is null, an exception is thrown. if (command = = null) throw new NullPointerException (); Gets the int value corresponding to the CTL. The int value holds the "number of tasks in the thread pool" and the "Wire pool state" information int c = Ctl.get (); When the number of tasks in the thread pool < core pool size is less than corepoolsize tasks in the thread pool. Creates a new thread by Addworker (command, true) and adds the task (command) to the thread, and then starts the thread to perform the task. if (Workercountof (c) < corepoolsize) {if (Addworker (command, True)) return; c = Ctl.get (); }///When the number of tasks in the thread pool >= "core pool Size",//And when the thread pool is in allowed state, try adding the task to the blocking queue. if (IsRunning (c) && workqueue.offer (command)) {//Confirm the thread pool status again, delete the task if the thread pool terminates abnormally, and then execute the content of the corresponding Deny policy through reject (). int recheck = Ctl.get (); if (! isrunning (Recheck) && Remove (command)) reject (command); Otherwise, if the number of tasks in the thread pool is 0, a new thread is tried by Addworker (null, FALSE), and the task for the new thread is null. else if (workercountof (recheck) = = 0) Addworker (null, FALSE); Create a new thread by Addworker (command, FALSE) and add the Task (command) to the thread;Start the thread to perform the task. If Addworker (command, false) execution fails, the content of the corresponding deny policy is executed through reject (). else if (!addworker (command, False)) reject (command);}
Description : The Role of Execute () is to add the task to the thread pool for execution. It will be processed in 3 different situations:
Scenario 1 -If the thread pool is in the number of tasks < core pool size, which is less than corepoolsize tasks in the pool of threads, create a new thread and add the task to the thread for execution.
Scenario 2 --If the "number of tasks in the thread pool" >= "core pool Size" and "thread pool is allowed", then the task is added to the blocking queue to block the wait. In that case, the status of the thread pool is confirmed again, and the task is removed from the blocking queue if the thread pool state that is read for the 2nd time and the thread pool state that is read for the 1th time are different.
Case 3 --not in either of the above two cases. In this case, you try to create a new thread and add the task to the thread to execute it. If execution fails, the task is rejected by reject ().
2. Addworker ()
The source code of Addworker () is as follows:
Private Boolean Addworker (Runnable Firsttask, Boolean core) {retry://Update the "thread pool status and Count" tag, which updates the CTL. for (;;) {//Gets the int value corresponding to the CTL. The int value holds the "number of tasks in the thread pool" and the "Wire pool state" information int c = Ctl.get (); Gets the thread pool status. int rs = runstateof (c); Validity Check if (rs >= SHUTDOWN &&! (rs = = SHUTDOWN && Firsttask = = null &&! workqueue.isempty ())) return false; for (;;) {//Gets the number of tasks in the thread pool. int WC = Workercountof (c); Returns False if the number of tasks in the thread pool exceeds the limit. if (WC >= Capacity | | WC >= (Core corepoolsize:maximumpoolsize)) return false; The value of C is +1 by using the CAS function. If the operation fails, the loop exits. if (Compareandincrementworkercount (c)) break retry; c = Ctl.get (); Re-read CTL//Check the thread pool status, if it is different from the previous state, start again from retry. 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; Add tasks to the thread pool, and start the threads where the tasks are located. try {final Reentrantlock mainlock = This.mainlock; Creates a new worker and specifies the first task that Firsttask is the worker. w = new Worker (firsttask); Gets the thread that the worker corresponds to. Final Thread t = w.thread; if (t! = null) {//Get lock Mainlock.lock (); try {int c = ctl.get (); int rs = runstateof (c); Confirm "Thread pool status" if (Rs < SHUTDOWN | | (rs = = SHUTDOWN && Firsttask = = null)) {if (t.isalive ())//PreCheck that T is startable throw new Illegalthreadstatee Xception (); Add the Worker object (W) to the Worker collection (workers) of the thread pool Workers.add (w); Update Largestpoolsize int s = workers.size (); if (S > largestpoolsize) largestpoolsize = s; Workeradded = true; }} finally {//release lock Mainlock.unlock (); }//If the task is successfully added to the thread pool, the thread that contains the task is started. if (workeradded) {T.start (); Workerstarted = true; }}} finally {if (! workerstarted) addworkerfailed (w); }//Returns whether the task is started. return workerstarted;}
Description :
The role of Addworker (Runnable Firsttask, Boolean core) is to add a task (firsttask) to the thread pool and start the task.
Core is true, the corepoolsize is the limit, if "the number of tasks in the thread pool >=corepoolsize", the return False;core to False, then the maximumpoolsize as the boundary, if " The number of tasks already in the thread pool >=maximumpoolsize "returns false.
Addworker () continuously attempts to update the CTL state through a for loop, and the CTL records the number of tasks in the thread pool and the thread pooling state.
After the update succeeds, the task is added to the thread pool through the try module and the thread where the task is started.
From Addworker (), we can clearly see that the thread pool creates a worker object for a task when it adds a task, while a Workder object contains a thread object. (01) Adding a Worker object to the thread's workers collection enables the task to be added to the thread pool. (02) The task is performed by starting the thread threads corresponding to the worker.
3. Submit ()
To add a point, the submit () is actually implemented by invoking execute (), with the following source code:
Public future<?> Submit (Runnable Task) { if (task = = null) throw new NullPointerException (); runnablefuture<void> ftask = newtaskfor (task, null); Execute (ftask); return ftask;}
(iii) Close the thread pool
The source code of shutdown () is as follows:
public void shutdown () { final reentrantlock mainlock = This.mainlock; Get lock Mainlock.lock (); try { //check whether the thread pool's threads have permissions. checkshutdownaccess (); Sets the status of the thread pool to off state. advancerunstate (SHUTDOWN); Threads that are idle in the thread pool. interruptidleworkers (); The hook function does not have any action in the Threadpoolexecutor. OnShutdown ();//hook for Scheduledthreadpoolexecutor } finally { //release lock Mainlock.unlock (); } Attempt to terminate thread pool tryterminate ();}
Description : The role of Shutdown () is to close the thread pool.
Java-"Juc thread pool" threadpoolexecutor principle parsing