Multithreading and high concurrency learning: ThreadPoolExecutor source code analysis

foreword

The thread pool is widely used in work, and learning its source code can better grasp the ideas related to concurrency.

text

Source Code Analysis——Basic Attributes

// ctl=11100000  00000000  00000000  00000000
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
//COUNT_BITS=29
private static final int COUNT_BITS = Integer.SIZE - 3;
//(1 << COUNT_BITS)     00100000  00000000  00000000  00000000
//(1 << COUNT_BITS)-1   00011111 11111111	11111111 11111111	
private static final int CAPACITY   = (1 << COUNT_BITS)  - 1;

//大小顺序为:RUNNING<SHUTDOWN<STOP<TIDYING<TERMINATED
// runState is stored in the high-order bits
// RUNNING= 11100000  00000000  00000000  00000000
private static final int RUNNING    = -1 << COUNT_BITS;
// SHUTDOWN = 00000000	00000000 00000000 00000000	
private static final int SHUTDOWN   =  0 << COUNT_BITS;
// STOP= 00100000  00000000  00000000  00000000
private static final int STOP       =  1 << COUNT_BITS;
// TIDYING= 01000000  00000000  00000000  00000000
private static final int TIDYING    =  2 << COUNT_BITS;
// TERMINATED= 01100000  00000000  00000000  00000000
private static final int TERMINATED =  3 << COUNT_BITS;

// Packing and unpacking ctl
//最终值大小取决于高三位
private static int runStateOf(int c)     {
    
     return c & ~CAPACITY; }
//最终值大小取决于低29位
private static int workerCountOf(int c)  {
    
     return c & CAPACITY; }
private static int ctlOf(int rs, int wc) {
    
     return rs | wc; }

Source code analysis——execute

public void execute(Runnable command) {
    
    
        if (command == null)
            throw new NullPointerException();
		
        int c = ctl.get();
    	//判断工作线程数量是否小于核心线程数
        if (workerCountOf(c) < corePoolSize) {
    
    
            //添加为核心线程,true参数代表是添加一个核心线程
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
    	//到这里证明当前工作线程超过了核心线程数
    	//判断如果线程池是处于运行状态,则将任务添加到工作队列中
        if (isRunning(c) && workQueue.offer(command)) {
    
    
            //重新检查
            int recheck = ctl.get();
            //如果线程池不是运行状态,则将任务从工作队列中移除掉,并执行拒绝策略
            if (! isRunning(recheck) && remove(command))
                reject(command);
            //判断当前的工作线程是否为0,如果为0创建一个新的工作线程用来消费处理队列中的任务
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
    	//走到这里并且能添加成功,证明此时的队列已经满了
    	//添加失败则执行拒绝策略
        else if (!addWorker(command, false))
            reject(command);
    }

Process summary:

1. If the current idle worker thread is less than the number of core threads, create a core thread and run the task directly

2. If the current idle worker thread is greater than the number of core threads, the thread pool is in the running state, and the task is thrown into the queue, waiting for consumption

3. Repeat the check to determine whether the thread pool status is running. If not, remove the tasks added to the queue above.

4. If the current idle worker thread is 0, create a non-core worker thread. After creation, the worker thread will consume tasks in the queue

5. If the task queue in the thread is full, try to add a non-core worker thread to process directly

Source code analysis - addWorker

private boolean addWorker(Runnable firstTask, boolean core) {
    
    
    //外层循环标记
    retry:
    for (;;) {
    
    
        int c = ctl.get();
        //计算此时线程池的运行状态
        int rs = runStateOf(c);

        // Check if queue empty only if necessary.
        //这里换种写法好理解写
        // if(rs>=SHUTDOWN){
    
    
        //     这里控制除了SHUTDOWN之外的其它状态,都不能添加新的工作线程
        //     if(rs != SHUTDOWN){
    
    
        //         return false;
        //     }
        //	   能到这里证明此时线程池状态为SHUTDOWN
        //	   如果任务为空,而队列不为空这种情况代表是创建新的非核心工作线程来消费处理队列,如:addWorker(null, false);
        //     if(!(firstTask == null&&!workQueue.isEmpty()){
    
    
        //         return false;
        //     }
        //  }
        
        if (rs >= SHUTDOWN &&
            ! (rs == SHUTDOWN &&
               firstTask == null &&
               ! workQueue.isEmpty()))
            return false;

        for (;;) {
    
    
            //计算当前工作线程数量
            int wc = workerCountOf(c);
            //判断工作线程总数量(包括核心线程)不能大于最大线程池数量阈值,或者核心工作线程数量不能大于核心工作线程的最大阈值
            if (wc >= CAPACITY ||
                wc >= (core ? corePoolSize : maximumPoolSize))
                return false;
            //使用CAS将工作线程数量+1
            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
        }
    }

    boolean workerStarted = false;
    boolean workerAdded = false;
    Worker w = null;
    try {
    
    
        //创建工作线程,将任务放到工作线程中
        w = new Worker(firstTask);
        //thread中的Runnable就是Worker
        final Thread t = w.thread;
        if (t != null) {
    
    
            //加锁,这样可以防止多线程情况下,其它线程调用了shutdown()方法,shutdownNow()方法
            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
    
    
                // Recheck while holding lock.
                // Back out on ThreadFactory failure or if
                // shut down before lock acquired.
                //重新获取状态
                int rs = runStateOf(ctl.get());
				//如果线程池处于运行状态,或者线程池处于SHUTDOWN状态并且任务参数为null这种情况(创建非核心工作线程来消费队列)
                if (rs < SHUTDOWN ||
                    (rs == SHUTDOWN && firstTask == null)) {
    
    
                    if (t.isAlive()) // precheck that t is startable
                        throw new IllegalThreadStateException();
                    //将工作线程添加到集合中
                    workers.add(w);
                    //记录线程池中曾经存在的最大工作线程数量
                    int s = workers.size();
                    if (s > largestPoolSize)
                        largestPoolSize = s;
                    //工作线程添加完毕
                    workerAdded = true;
                }
            } finally {
    
    
                mainLock.unlock();
            }
            if (workerAdded) {
    
    
                //开启调用work的run方法,而run方法调用了runWorker(this);
                t.start();
                workerStarted = true;
            }
        }
    } finally {
    
    
        //工作线程启动失败,则将该工作线程从集合中移除,并将当前工作线程数量-1
        if (! workerStarted)
            addWorkerFailed(w);
    }
    return workerStarted;
}

Process summary:

1. Check whether the current thread pool status is in the running state. If it is not in the running state, judge whether it is SHUTDOWN, and the task parameter is empty, and the queue is not empty (for the addWorker(null, false) scenario). In this case, it is allowed to create Worker threads, because the status of the thread pool is changed to SHUTDOWN immediately after the task is added to the queue. In this case, if the queue still has tasks that need to be consumed, one more worker thread can be started to help consume;

2. Try to add 1 to the total number of worker threads through CAS. If the addition of 1 is successful, it proves that the thread can be added successfully (to deal with multi-threaded scenarios), otherwise it keeps spinning and tries to add worker threads

3. Create a worker thread and set the task into it; since the Worker itself implements the Runnable interface, its thread attribute is to wrap itself into a Thread

4. Start the run method of the worker thread. Since runWorker(this) is called in the run method, this method is the core method of the real processor task

Source Code Analysis——runWorker

final void runWorker(Worker w) {
    
    
    	//获取当前的工作线程
        Thread wt = Thread.currentThread();
    	//获取任务
        Runnable task = w.firstTask;
    	//将任务置为空,因为后面执行完这个任务后,工作线程还会去处理队列中的任务
        w.firstTask = null;
    	//由于Worker继承了AQS,这里调用unlock(),实际是把AQS中的状态设置为0,此时调用shutdown或者shutdownNow方法时,可以获取到锁,将当前线程中断掉
        w.unlock(); // allow interrupts
        boolean completedAbruptly = true;
        try {
    
    
            //1、当前有任务处理,执行execute、submit传入的任务
            //2、从队列中获得到任务
            while (task != null || (task = getTask()) != null) {
    
    
                //获取到任务进行锁后,由于是非重入锁,此时不能中断在执行中的工作线程;所以SHUTDOWN状态下是没办法中断非空闲线程的;空闲线程由于没有lock所以可以被中断
                w.lock();
                // If pool is stopping, ensure thread is interrupted;
                // if not, ensure thread is not interrupted.  This
                // requires a recheck in second case to deal with
                // shutdownNow race while clearing interrupt
                //线程池状态为STOP或者STOP后面的状态时,不会再执行任务了
                //Thread.interrupted()会返回当前线程的中断标志,并且清除中断标志
                if ((runStateAtLeast(ctl.get(), STOP) ||
                     (Thread.interrupted() &&
                      //如果是STOP及其后面的状态则为true,!wt.isInterrupted()判断中断标志是否为false
                      runStateAtLeast(ctl.get(), STOP))) &&
                    !wt.isInterrupted())
                    //先当前线程中断
                    wt.interrupt();
                try {
    
    
                    //拓展方法,留给子类实现
                    beforeExecute(wt, task);
                    Throwable thrown = null;
                    try {
    
    
                        //执行任务
                        task.run();
                    } 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;
                    //处理完任务的数量+1
                    w.completedTasks++;
                    w.unlock();
                }
            }
            completedAbruptly = false;
        } finally {
    
    
            processWorkerExit(w, completedAbruptly);
        }
    }

Process summary

1. At the beginning, the state in AQS is set to 0, and when the shutdown or shutdownNow method is allowed to be called, the lock can be obtained and the current thread will be interrupted.

2. If there is currently an incoming task, execute it directly, otherwise go to the queue to get it. If it cannot be obtained, the current worker thread will be destroyed;

3. If the thread is not in the interrupt state, execute the task. If the execution is successful, the number of tasks processed by the current thread will be accumulated.

4. Finally, destroy the thread

Source code analysis - getTask

private Runnable getTask() {
    
    
    boolean timedOut = false; // Did the last poll() time out?

    for (;;) {
    
    
        //获取线程池状态
        int c = ctl.get();
        int rs = runStateOf(c);

        // Check if queue empty only if necessary.
        //如果线程池处于SHUTDOWN并且队列为空,则没有任务需要处理
        //如果线程池状态为STOP,TYDING,TERMINATED,则不需要在处理
        //以上两种情况会将当前的工作线程销毁掉,这里先将数量-1。在外层方法中的processWorkerExit进行销毁
        if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
    
    
            decrementWorkerCount();
            return null;
        }
		//统计当前工作线程数量
        int wc = workerCountOf(c);

        // Are workers subject to culling?
        //timed为true时只有两种可能,一种是allowCoreThreadTimeOut=true允许核心线程在规定时间内获取不到任务时,进行销毁,此时的核心线程就跟非核心线程没有什么区别了
        //另一种情况是,核心线程不允许超时,也就是一直保持核心线程处于活跃状态,并且存在非核心线程(比较总工作线程数是否大于核心线程数)
        //核心工作核心和非核心工作线程没有什么区别,只是最终一直处于活跃状态就是核心线程。刚开始是核心线程后面可能就转为非核心线程,最终可能被销毁。
        boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
		//1、超过最大线程池数量,直接销毁当前的工作线程
        //2、time为true代表允许超时销毁,而timeout=true代表获取任务超时,此时会判断工作线程数量是否大于1,如果<=1时,任务队列必须为空。这样判断的目的是为了保证将目前的工作线程销毁后,还存在线程可以处理任务,而如果任务都没有了,就不需要工作线程的存在了。
        if ((wc > maximumPoolSize || (timed && timedOut))
            && (wc > 1 || workQueue.isEmpty())) {
    
    
            if (compareAndDecrementWorkerCount(c))
                return null;
            continue;
        }

        try {
    
    
            //如果允许超时,则keepAliveTime时间内获取不到任务时,跳出来
            Runnable r = timed ?
                workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                workQueue.take();
            if (r != null)
                return r;
            //设置超时标识
            timedOut = true;
        } catch (InterruptedException retry) {
    
    
            timedOut = false;
        }
    }
}

Process summary:

1. If the thread pool is in SHUTDOWN and the queue is empty, there is no task to be processed, and the current worker thread can be destroyed at this time, or the thread pool status is STOP, TYDING, TERMINATED, then there is no need to process

2. Determine whether the current worker thread is allowed to timeout; there are two cases, one is allowCoreThreadTimeOut=true allows the core thread to set the timeout time when the queue is acquiring tasks, and destroy it after the timeout. At this time, the core thread is no different from the non-core thread What's the difference, because the core thread is always active, even if there are no tasks in the queue, it will wait; the second is that the core thread is not allowed to time out, and there are non-core threads (comparing whether the total number of working threads is greater than the number of core threads), then Timeout is allowed. The non-core worker thread sets the timeout period when acquiring the queue. When it expires, it will be destroyed;

Source code analysis——processWorkerExit

private void processWorkerExit(Worker w, boolean completedAbruptly) {
    
    
    //如果线程异常,则completedAbruptly=true,此时将工作线程数-1
    if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
        decrementWorkerCount();
	//加锁
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
    
    
        //将已完成任务数量汇总
        completedTaskCount += w.completedTasks;
        //移除集合中的工作线程
        workers.remove(w);
    } finally {
    
    
        mainLock.unlock();
    }
	//将符合条件的工作线程中断,并设置线程池最终状态
    tryTerminate();

    int c = ctl.get();
    //如果线程池状态为RUNNING或SHUTDOWN
    if (runStateLessThan(c, STOP)) {
    
    
        if (!completedAbruptly) {
    
    
            
        	// min表示最小线程数,若allowCoreThreadTimeOut为true表示设置了允许核心线程数超时,则最小核心线程数为0,否则就是corePoolSize值
            int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
            //如果队列中还有任务需要处理,则将最小核心数设置为1,保证有线程可以进行处理
            if (min == 0 && ! workQueue.isEmpty())
                min = 1;
            if (workerCountOf(c) >= min)
                return; // replacement not needed
        }
        //创建工作线程
        addWorker(null, false);
    }
}

Process summary:

1. If completedAbruptly=true, it proves that an exception has occurred, then the total number of worker threads will be -1; because if completedAbruptly=false, the process is executed normally, and the current thread is destroyed because the thread cannot find the task to execute , while the number of threads -1 step has been completed in the getTask() step;

2. Summarize the number of completed processing tasks

3. Interrupt the eligible worker threads and set the final state of the thread pool

4. If the state of the thread pool is RUNNING or SHUTDOWN, and the process is executed normally without exception, judge whether to allow the core thread to time out, because if the core thread is allowed to time out, then the core thread is no different from the non-core thread, and may be blocked because there is no task Destroy, at this time set the minimum number of threads to 0, otherwise set to the threshold of the number of core threads;

5. Determine whether there are tasks in the queue, and if so, reserve the minimum number of worker threads calculated in step 4 to execute queue tasks

Source code analysis——tryTerminate

final void tryTerminate() {
    
    
    for (;;) {
    
    
        int c = ctl.get();
        //SHUTDOWN状态下队列没有任务了 或者  状态为STOP会往下走
        if (isRunning(c) ||
            runStateAtLeast(c, TIDYING) ||
            (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
            return;
        //如果线程池存在工作线程,将工作线程中断
        if (workerCountOf(c) != 0) {
    
     // Eligible to terminate
            interruptIdleWorkers(ONLY_ONE);
            return;
        }

        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
    
    
            //将线程池状态设置为TIDYING
            if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
    
    
                try {
    
    
                    //执行中断钩子函数
                    terminated();
                } finally {
    
    
                    //将线程池状态设置为TERMINATED
                    ctl.set(ctlOf(TERMINATED, 0));
                    termination.signalAll();
                }
                return;
            }
        } finally {
    
    
            mainLock.unlock();
        }
        // else retry on failed CAS
    }
}

Process summary:

1. Determine whether the worker thread needs to be interrupted

  • The thread pool is running and does not need to be interrupted
  • The thread pool is in the SHUTDOWN state, but there are still tasks in the queue that have not been processed, so there is no need to interrupt
  • The TYDING and TEMINATED states do not need to be interrupted, because the STOP state before entering these two states has already performed the thread interruption operation

2. If there are worker threads in the thread pool, interrupt the worker threads

3. After locking, modify the thread pool status to set the thread pool status to TIDYING

4. After executing the hook function, set the thread pool status to TERMINATED

Source code analysis——shutdown

public void shutdown() {
    
    
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
    
    
        checkShutdownAccess();
        //设置线程池状态为SHUTDOWN
        advanceRunState(SHUTDOWN);
        //将所有工作线程中断标志设置为true
        interruptIdleWorkers();
        //尝试将工作线程打断
        onShutdown(); // hook for ScheduledThreadPoolExecutor
    } finally {
    
    
        mainLock.unlock();
    }
    //尝试中断,会中断空闲的线程因为空闲线程还没有lock
    tryTerminate();
}

Source code analysis——shutdownNow

public List<Runnable> shutdownNow() {
    
    
    List<Runnable> tasks;
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
    
    
        
        checkShutdownAccess();
        //设置线程池状态为STOP
        advanceRunState(STOP);
        //中断所有线程
        interruptWorkers();
        //清空队列任务
        tasks = drainQueue();
    } finally {
    
    
        mainLock.unlock();
    }
    //尝试中断,会中断空闲的线程因为空闲线程还没有lock,而那些有lock的由于队列任务被清空,执行完任务后也会被销毁
    tryTerminate();
    return tasks;
}

Summarize

We know from the source code above that core threads are essentially the same as non-core threads, just to keep several threads active and process tasks in the queue when there are fewer tasks, and the number of core threads is active state, you can process queue tasks at any time; but there is a case where the core thread will also be destroyed, that is, the "allow core thread timeout" flag is set, and the core thread at this time is no different from the non-core thread. After timeout, it will be destroyed, but if there are tasks in the queue, the minimum number of thread pools will be set to 1, and one thread in the thread pool can be used to process tasks;

From the source code, we can know that when the shutdown method is called, the state of the thread pool changes to the SHUTDOWN state. At this time, it will try to interrupt the thread in the idle state, that is, the thread without lock; and those threads holding the lock will continue to be in The tasks in the queue are destroyed until the tasks are consumed; new tasks are not allowed to be added in the SHUTDOWN state, but tasks that have been added to the queue are allowed to be executed;

After calling the shutdownNow method, the state of the thread pool changes to STOP, and all idle threads are interrupted at this time, and the queue tasks are cleared. And those that are still in the running state are destroyed after they are executed and cannot get the task.

When there are no working threads in all thread pools, and the state is STOP, change the state to TYDING through CAS, and change the thread pool state to TERMINATED after executing the hook function

Guess you like

Origin blog.csdn.net/weixin_45031612/article/details/130756955