ThreadPoolExecutor
ThreadPoolExecutor is the parent of all thread pool implementations. Let's first look at the constructor
Constructional parameters
- corePoolSize: Number of Thread Cores
- Maximum PoolSize: Maximum number of threads
- Keep AliveTime: When a thread is idle, it will only survive if the number of threads is greater than corePoolSize
- Unit: unit of survival time
- workQueue: Blocking queue for tasks
- threadFactory: The project of creating threads, naming threads
- handler: When the thread pool is full, you can also customize the strategy for selecting new tasks, such as throwing exceptions, discarding current tasks, discarding the oldest tasks in the blocking queue, etc.
Technological process
- Determine whether the number of corePoolSize threads exceeds the number of corePoolSize threads created
- If the number of threads exceeds the core number, the queue will be filled or not and put into the queue.
- The queue is full, and if it exceeds maximumPoolSize, create threads without
- Overtake, execute according to strategy
Source code parsing
//32. The first three bits are the state of the thread pool, and the last three are the number of threads. private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); private static final int COUNT_BITS = Integer.SIZE - 3;//28 private static final int CAPACITY = (1 << COUNT_BITS) - 1;00011111 11111111 11111111 11111110 //- The binary of 1 is 1111111111 11111 11111 11111 11111 11111 11111 11 11111 11 private static final int RUNNING = -1 << COUNT_BITS;//- As mentioned above, after moving 28 bits to the left, it will be 111 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 private static final int SHUTDOWN = 0 << COUNT_BITS;//0 moved 28 bits left, or 0,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000 private static final int STOP = 1 << COUNT_BITS;//00100000 00000000 00000000 00000000 private static final int TIDYING = 2 << COUNT_BITS;//01000000 00000000 00000000 00000000 private static final int TERMINATED = 3 << COUNT_BITS;//01100000 00000000 00000000 00000000 private static int runStateOf(int c) { return c & ~CAPACITY; }//~ CAPACITY is 1100,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000. private static int workerCountOf(int c) { return c & CAPACITY; }//And finish, is the number of threads private static int ctlOf(int rs, int wc) { return rs | wc; } private static boolean isRunning(int c) { return c < SHUTDOWN;//Less than 0, RUNNING, RUNNING=-1 }
execute method
public void execute(Runnable command) { if (command == null) throw new NullPointerException(); int c = ctl.get(); if (workerCountOf(c) < corePoolSize) {//If the number of threads is less than the number of thread cores if (addWorker(command, true))//Increase task success, return to true, unsuccessful, continue return; c = ctl.get(); } //Judgment queue if (isRunning(c) && workQueue.offer(command)) {//If the thread pool is still running and can be inserted into the queue int recheck = ctl.get(); if (! isRunning(recheck) && remove(command))//Thread pool is not running, remove the task just inserted reject(command);//Implementation strategy else if (workerCountOf(recheck) == 0)// addWorker(null, false); } //The queue is full, judging the maximum number of threads else if (!addWorker(command, false)) reject(command);//Implementation strategy }
addWorker method
private boolean addWorker(Runnable firstTask, boolean core) {//core is true, use corePoolSize to judge, otherwise use maximumPoolSize retry: for (;;) { int c = ctl.get(); int rs = runStateOf(c);//Get the current thread state // Check if queue empty only if necessary. if (rs >= SHUTDOWN && // It's STOP, TIDYING, TERMINATED. No tasks are allowed in at this time. ! (rs == SHUTDOWN && firstTask == null && ! workQueue.isEmpty()))// return false; for (;;) { int wc = workerCountOf(c); if (wc >= CAPACITY || wc >= (core ? corePoolSize : maximumPoolSize)) return false;//No more threads than the core or maximum number of threads if (compareAndIncrementWorkerCount(c))//Return true, indicating success, and jump out of the retry loop break retry; //Failed, indicating that the thread is occupied by other symbolic conditions, and then determine whether the thread state is the same as before, different retrieve, jump to retry c = ctl.get(); // Re-read ctl 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; try { w = new Worker(firstTask); final Thread t = w.thread; if (t != null) { final ReentrantLock mainLock = this.mainLock; mainLock.lock();//Acquisition locks try { int rs = runStateOf(ctl.get());//Get the state of the thread pool if (rs < SHUTDOWN || (rs == SHUTDOWN && firstTask == null)) { if (t.isAlive()) // run is not started by start throw new IllegalThreadStateException(); workers.add(w);//Additional hashset int s = workers.size(); if (s > largestPoolSize) largestPoolSize = s;//Update the current maximum workerAdded = true;//Increase success } } finally { mainLock.unlock(); } if (workerAdded) { t.start();//Start threads workerStarted = true;//Successful start-up } } } finally { if (! workerStarted) addWorkerFailed(w);//Failure, thread count - 1, remove from hashset, and try Terminate } return workerStarted; }
runWorker Method
When t.start(); is executed above, the following method is called through the run method
final void runWorker(Worker w) { Thread wt = Thread.currentThread(); Runnable task = w.firstTask; w.firstTask = null; w.unlock(); // allow interrupts boolean completedAbruptly = true; try { while (task != null || (task = getTask()) != null) {//Tasks are not empty or acquired tasks are not empty. w.lock(); 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();//Call the run method, which does not pass start, that is, no new thread is started } 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++;//Number of tasks completed plus 1 w.unlock();//release } } completedAbruptly = false; } finally { processWorkerExit(w, completedAbruptly);//Remove w, when task is empty, such as when thread pool status stops or too many threads are started } }
getTask method
When Worker first starts, it calls the run method, and then it gets tasks from the queue all the time.
private Runnable getTask() { boolean timedOut = false; // Did the last poll() time out? for (;;) { int c = ctl.get(); int rs = runStateOf(c);//Get the current thread pool status // Check if queue empty only if necessary. if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {// decrementWorkerCount();//Number of threads - 1 return null; } int wc = workerCountOf(c);//Number of threads //allowCoreThreadTimeOut is true, indicating that the number of threads should be determined by whether the number of keepAliveTime threads exceeds the number of core threads. boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;//Does it exceed the number of core threads? if ((wc > maximumPoolSize || (timed && timedOut))//Over the maximum number of threads && (wc > 1 || workQueue.isEmpty())) { if (compareAndDecrementWorkerCount(c))//Number of threads - 1 return null;//Return empty continue; } try { Runnable r = timed ? workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : workQueue.take();//Acquisition task if (r != null) return r; timedOut = true; } catch (InterruptedException retry) { timedOut = false; } } }