线程池ThreadPoolExcutor生命周期

773 阅读2分钟

关于线程池ThreadPoolExecutor的生命周期,其转换图如下。

image-20211215230403780.png

shutdown方法

shutdown()方法源码十分简单

public void shutdown() {
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        checkShutdownAccess();
        advanceRunState(SHUTDOWN);
        interruptIdleWorkers();
        onShutdown(); // hook for ScheduledThreadPoolExecutor
    } finally {
        mainLock.unlock();
    }
    tryTerminate();
}

checkShutdownAccess()方法是安全权限管理相关的,onShutdown()在ThreadPoolExecutor中是一个空方法。主要需要了解的就是advanceRunState(SHUTDOWN),interruptIdleWorkers() 方法。

属性ctl是一个AtomicInteger类,它同时包含两部分的信息:线程池的运行状态 (runState) 和线程池内有效线程的数量 (workerCount),高3位保存runState,低29位保存workerCount,两个变量之间互不干扰。用一个变量去存储两个值,可避免在做相关决策时,出现不一致的情况,不必为了维护两者的一致,而占用锁资源

private void advanceRunState(int targetState) {
    for (;;) {
        int c = ctl.get();
        if (runStateAtLeast(c, targetState) ||
            ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c))))
            break;
    }
}

另外,从源码中看到:

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;

各个状态在高3位分别对应:

RUNNING111
SHUTDOWN000
STOP001
TIDYING010
TERMINATED011

所以advanceRunState方法主要是将ctl状态设置为"targetState",在shutdown方法中就是设为SHUTDOWN。

这里 if (runStateAtLeast(c, targetState) || ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c)))) 使得只有一个线程能够成功将线程池设为targetState状态。

接下来是interruptIdleWorkers方法,如下:

private void interruptIdleWorkers() {
    interruptIdleWorkers(false);
}

其中interruptIdleWorkers方法如下:

private void interruptIdleWorkers(boolean onlyOne) {
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        for (Worker w : workers) {
            Thread t = w.thread;
            if (!t.isInterrupted() && w.tryLock()) {
                try {
                    t.interrupt();
                } catch (SecurityException ignore) {
                } finally {
                    w.unlock();
                }
            }
            if (onlyOne)
                break;
        }
    } finally {
        mainLock.unlock();
    }
}

属性worker是一个HashSet,对HashSet中的每个Worker,在worker的所在线程不是interrupted的情况下**(!t.isInterrupted())**,会去调用worker的tryLock()方法,用来判断该worker是否在工作。具体原理需要结合Worker的工作流程来解释。

如图,所示。当我们调用threadPoolExecutor.execute( Runnable runnable )方法给线程池提交任务的时候,最终会在一个另外的“工作线程”中执行runWorker方法

threadPoolExecutor.drawio.png

runWorker方法的代码如下:

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) {
            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
            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();
                } 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);
    }
}

可以看到,源代码的注释里也写了 w.unlock(); 是为了 允许中断。那它为什么能允许中断呢?那是因为Worker类继承了AbstractQueuedSynchronizer类,Worker类的unlock方法会直接将AQS的state变量设为0,然后返回true。 所以当state为0的时候表示这个Worker的所在线程是可以被中断的。

Worker类的unlock逻辑

public void unlock()      { release(1); }

  public final boolean release(int arg) {
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

  protected boolean tryRelease(int unused) {
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
 }

另一方面,在Worker类的while循环中,如果Worker线程成功获取到task,那么它会首先调用Woker类的lock方法。lock方法会尝试把state从0设为1,如果成功就表示当前的Worker所在的线程正在工作。

Worker类的lock方法逻辑

public void lock()        { acquire(1); }


   public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }
    
       protected boolean tryAcquire(int unused) {
            if (compareAndSetState(0, 1)) {
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

所以回头看之前的interruptIdleWorkers()方法,就能明白这里:

private void interruptIdleWorkers(boolean onlyOne) {
   
   if (!t.isInterrupted() && w.tryLock()) 
   ......
}

是怎样判断出当前的Worker线程是空闲的了

shutdownNow方法

源码如下:

public List<Runnable> shutdownNow() {
    List<Runnable> tasks;
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        checkShutdownAccess();
        advanceRunState(STOP);
        interruptWorkers();
        tasks = drainQueue();
    } finally {
        mainLock.unlock();
    }
    tryTerminate();
    return tasks;
}

可以看到,与shutdonw方法类似,shutdownNow方法也是先检查安全权限,然后用advanceRunState方法将状态设为STOP。

但是与shutdown方法不同的是,这里的是直接用interruptWorkers方法中断Workers工作线程,而不是像shutdown方法那样只中断那些空闲的工作线程。

interruptWorkers逻辑如下:

private void interruptWorkers() {
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        for (Worker w : workers)
            w.interruptIfStarted();
    } finally {
        mainLock.unlock();
    }
}

 void interruptIfStarted() {
            Thread t;
            if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
                try {
                    t.interrupt();
                } catch (SecurityException ignore) {
                }
            }
        }

在Worker的构造方法中可以看到,一开始的state值是-1。后面的注释也有说明此时禁止被中断知道Worker工作线程跑起来。

Worker(Runnable firstTask) {
    setState(-1); // inhibit interrupts until runWorker
    this.firstTask = firstTask;
    this.thread = getThreadFactory().newThread(this);
}

那什么时候会可以被中断呢?如下:

runWorker(Worker w)方法中一开始会调用unlock方法。前面也有讲解过,unlock会调用tryRealease,在此方法中会设置state为0

final void runWorker(Worker w) {
    Thread wt = Thread.currentThread();
    Runnable task = w.firstTask;
    w.firstTask = null;
    w.unlock(); // allow interrupts
    
..................    
    
    
}

//tryRelease 方法设置state为0
protected boolean tryRelease(int unused) {
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }

由此可见interruptWorkers方法直接就会把所有启动了的工作线程Worker给中断掉。

接着,会把阻塞队列中的任务清空出来,代码比较简单:

private List<Runnable> drainQueue() {
    BlockingQueue<Runnable> q = workQueue;
    ArrayList<Runnable> taskList = new ArrayList<Runnable>();
    q.drainTo(taskList);
    if (!q.isEmpty()) {
        for (Runnable r : q.toArray(new Runnable[0])) {
            if (q.remove(r))
                taskList.add(r);
        }
    }
    return taskList;
}

Ref:

Java线程池实现原理及其在美团业务中的实践 (qq.com)

(11条消息) AQS acquire(int arg) 深度解析_D_下潜的博客-CSDN博客