线程池 Worker 生命周期

Worker 生命周期

线程池的5种状态

// Integer.SIZE 为 32  COUNT_BITS = 29
private static final int COUNT_BITS = Integer.SIZE - 3; 
// 前三位0,后29位都为1
private static final int CAPACITY   = (1 << COUNT_BITS) - 1; 

// 线程池运行状态
// 前三位 111,后29位都是0,第一位为1表示负数
private static final int RUNNING    = -1 << COUNT_BITS; 
// 32 为都为 0
// SHUTDOWN: Don't accept new tasks, but process queued tasks
private static final int SHUTDOWN   =  0 << COUNT_BITS; 
// 前三位 001,后29位都为0
// STOP: Don't accept new tasks, don't process queued tasks, and interrupt in-progress tasks
private static final int STOP       =  1 << COUNT_BITS; 
// 前三位 010,后29位都是0
// TIDYING: All tasks have terminated, workerCount is zero, the thread transitioning to state TIDYING will run the terminated() hook method
private static final int TIDYING    =  2 << COUNT_BITS; 
// 前三位 011,后29位都是0
// TERMINATED: terminated() has completed
private static final int TERMINATED =  3 << COUNT_BITS; 

// & 位与运算符 两位都为1,结果才为1
// ~CAPACITY 前三位1 后面29位为0
private static int runStateOf(int c)     { return c & ~CAPACITY; }
private static int workerCountOf(int c)  { return c & CAPACITY; }
// | 位或运算符,两个位都为0,结果才为0
private static int ctlOf(int rs, int wc) { return rs | wc; }

Worker 添加

Worker 添加的执行逻辑在 execute(Runnable command) 函数中

if (workerCountOf(c) < corePoolSize) {
  if (addWorker(command, true)) return;
}

如果 Worker 数量小于核心线程数量,则直接添加。

if (isRunning(c) && workQueue.offer(command)) {
  int recheck = ctl.get();
  if (! isRunning(recheck) && remove(command))
    reject(command);
  else if (workerCountOf(recheck) == 0)
    addWorker(null, false);
}

如果线程池处于 RUNNING 状态并且添加任务到 workQueue 成功,然后重新检查线程池状态如果状态改变,并且移除任务成功则走饱和策略。如果线程池装备没变,或者改变了但是移除任务不成功,并且线程池中 Worker 数量为 0,则添加一个空任务的 Worker,让队列中的任务继续执行。

public void execute(Runnable command) {
  if (command == null) throw new NullPointerException();
  int c = ctl.get();
  // 小于 corePoolSize 直接添加
  if (workerCountOf(c) < corePoolSize) {
    // 添加成功直接返回
    if (addWorker(command, true))return;
    c = ctl.get();
  }
  // 处于 Running 状态并且添加 workQueue 成功
  if (isRunning(c) && workQueue.offer(command)) {
    int recheck = ctl.get();
    // 不在 Running 状态并且移除任务成功,则走饱和策略
    if (! isRunning(recheck) && remove(command))
      reject(command);
    else if (workerCountOf(recheck) == 0) // Worker 数量为0,添加一个空任务的 Worker,使添加到 workQueue 的任务能够被执行
      addWorker(null, false);
  } else if (!addWorker(command, false)) // workQueue 满了(不在 Runing 状态是无法添加有任务的 Worker 的)
    reject(command);
}
// rs > SHUTDOWN
// || (rs == SHUTDOWN && firstTask != null) 
// || (rs == SHUTDOWN && workQueue.isEmpty()) 如果 workQueue 不空,即使是 SHUTDOWN 状态也可以创建 Worker
if (rs >= SHUTDOWN && 
! (rs == SHUTDOWN && firstTask == null && ! workQueue.isEmpty())) return false;

任务获取

在解析 Worker 执行之前先得了解任务获取,下面是 getTask() 函数解析:

if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
  decrementWorkerCount();
  return null;
}

判断线程池状态,如果是 >= STOP 或者是 SHUTDOWN 状态并且任务队列为空,Worker 数量减一,并返回 null

boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
  if (compareAndDecrementWorkerCount(c)) return null;
  continue;
}
  1. allowCoreThreadTimeOutfalse 表示核心线程是闲置的也不会被回收,true 表示如果等待任务时间过长也会被回收。
  2. timed 表示如果核心线程可以回收或者总线程数大于核心线程数,那么获取任务时会设置超时时间
  3. timedOut 表示获取任务时是否超时。
try {
  Runnable r = timed ? workQueue.poll(keepAliveTime,TimeUnit.NANOSECONDS) : workQueue.take();
  if (r != null) return r;
  timedOut = true;
} catch (InterruptedException retry) {
  timedOut = false;
}

如果成功获取任务则返回,如果超时则设置 timedOut = true,如果阻塞队列响应线程中断,则设置 timedOut = false

Worker 执行

Worker 执行的主要内容在 runWorker(Worker w) 函数中,下面是具体解析:

w.unlock(); // allow interrupts

这行代码用来表明该线程时可以被中断的,首先 Worker 继承了 AQS,并且在构造函数中调用了 setState(-1) 用于禁止中断,同时要想中断 Worker 有两种方式,一种是 tryLock()(通过 CAS 方式把 state 从 0 设置为 1) 然后调用 interrupt(),一种是判断 getState() >= 0 然后调用 interrupt(),而 unlock() 作用就是把 state 设置为 0,使得可以被中断。

while (task != null || (task = getTask()) != null) {
  w.lock();
  // 执行任务
  w.unlock();
}

用来从任务队列中获取新任务,并且在执行任务时加锁。这里加锁的目的是表明该 Worker 不是闲置的 Worker,因为闲置的 Worker 可能会被回收。

if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() && runStateAtLeast(ctl.get(), STOP))) 
&& !wt.isInterrupted())
  wt.interrupt();
  • 如果线程池状态是 >= STOP 并且线程没有中断,那么调用线程中断
  • 如果线程池状态是 < STOP,那么清除中断标志,如果线程之前不是中断状态,则继续执行;如果线程之前是中断状态,那么会判断线程池状态是否是 >= STOP,如果是,调用线程中断,否则继续执行。
    你可能会问什么情况下会发生:线程解除中断状态并且线程池状态会从 < STOP,变成 >= STOP?假如线程池突然调用了 shutdownNow()可能会发生上面的情况,作用是为了在调用 shutdownNow() 的时候立即中断线程。
beforeExecute(wt, task);
try{
  task.run();
} finally {
  afterExecute(task, thrown);
}

beforeExecute()afterExecute() 分别是任务执行前和执行后的调用,可以用来做监控。

Worker 回收

Worker 回收的主要执行逻辑在 processWorkerExit

processWorkerExit(Worker w, boolean completedAbruptly){
  // completedAbruptly 为 true 代表是任务异常导致的
  if (completedAbruptly) decrementWorkerCount();
  completedTaskCount += w.completedTasks;
  // 回收 Worker
  workers.remove(w);
  if (runStateLessThan(c, STOP)) {
    // 如果是正常终止的,并且还有 Worker,则不添加替代 Worker
    if (!completedAbruptly) {
      int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
      if (min == 0 && ! workQueue.isEmpty()) min = 1;
      if (workerCountOf(c) >= min) return;
    }
    addWorker(null, false);
  }
}

如果在执行 task.run() 出现异常,或者 getTask() 返回 null 就会执行上面的函数。Worker 就会被回收掉。

posted @ 2020-11-26 15:39  aaro0n  阅读(204)  评论(0)    收藏  举报