ThreadPoolExecutor-学习

92 阅读7分钟

Worker

实现Runnable,继承AQS;

Worker是对任务的封装,执行完一个任务,可以继续执行等待队列中的其它任务;

通过继承AQS,实现了非重入的互斥锁,实现互斥锁主要目的是为了中断的时候判断线程是在空闲还是运行。

状态变量:ctl

状态设计与ReentrantReadWriteLock设计相同,读写锁是高16位表示读锁状态,低16位表示写锁状态

# AtomicInteger 原子型,操作具有原子性
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));

/**
 * 高3位表示:线程池状态、低29位表示:工作的线程数
 * 线程池最大容量:1^29 -1
 * 为什么要这么拆分:线程池的状态有5个,需要3位二进制
 */
private static final int COUNT_BITS = Integer.SIZE - 3;
private static final int CAPACITY   = (1 << COUNT_BITS) - 1;
  
/**
 * 获取线程池状态,当前状态与最大容量(29个1)取反后 进行【与计算】,前29位不会参与计算
 *    1111 1111 1111 1111 1111 1111 1111 1111 
 *  & 1110 0000 0000 0000 0000 0000 0000 0000 
 *    1110 0000 0000 0000 0000 0000 0000 0000  
 */   
private static int runStateOf(int c)     { return c & ~CAPACITY; }

/**
 * 1.获取当前工作线程数,当前状态与最大容量(29个1)进行【与计算】,前3位不会参与计算
 *    1111 1111 1111 1111 1111 1111 1111 1111 
 *  & 0001 1111 1111 1111 1111 1111 1111 1111
 *    0001 1111 1111 1111 1111 1111 1111 1111
 * 2.当前线程工作数包含:核心线程与非核心线程
 */
private static int workerCountOf(int c)  { return c & CAPACITY; }

/**
 * 通过【或计算】将runstate、workerCount 合并成一个变量
 *    1110 0000 0000 0000 0000 0000 0000 0000 
 *  | 0001 1111 1111 1111 1111 1111 1111 1111
 *    1111 1111 1111 1111 1111 1111 1111 1111
 */ 
private static int ctlOf(int rs, int wc) { return rs | wc; }


/**
 * 当前工作线程数自增,在#addWorker时会被调用
 */
 private boolean compareAndIncrementWorkerCount(int expect) {
    return ctl.compareAndSet(expect, expect + 1);
}

/**
 * 当前工作线程数自减
 */
private boolean compareAndDecrementWorkerCount(int expect) {
    return ctl.compareAndSet(expect, expect - 1);
}

线程池状态

// 线程池能够接受任务,并且可以运行队列中的任务  
private static final int RUNNING    = -1 << COUNT_BITS;
// 不接受新的任务,但是等待队列里的任务还是会执行,#shutDown后的状态
private static final int SHUTDOWN   =  0 << COUNT_BITS;
// 不接受新的任务,不会执行队列中的任务,并且尝试去中断正在运行的任务,#shutDownNow后的状态
private static final int STOP       =  1 << COUNT_BITS;
// 所有任务都已经终止,workCount值为0,转到TIDYING状态的线程即将要执行terminated()钩子方法
private static final int TIDYING    =  2 << COUNT_BITS;
// #terminated 执行结束
private static final int TERMINATED =  3 << COUNT_BITS;
​
五种状态的转变:
RUNNING -> SHUTDOWN:调用了#shutdown方法,或者线程池实现了finalize方法,在里面调用了#shutdown。 
(RUNNING or SHUTDOWN) -> STOP:调用了#shutdownNow 
SHUTDOWN -> TIDYING:当队列和线程池均为空的时候 
STOP -> TIDYING:当线程池为空的时候 
TIDYING -> TERMINATED:terminated()钩子方法调用完毕
​

#execute

/**
 * 1. 如果当前工作线程数 < 核心线程数,标记为核心线程,创建Worker执行;
 * 2. 如果当前工作线程数 >= 核心线程数,添加到等待队列;
 * 3. 如果当前工作线程数 >= 核心线程数 且 等待队列也满了,标记为非核心线程,创建Worker执行
 * 4. 如果第3步返回false(当前工作线程数 > 指定的最大线程数),则执行拒绝策略
 */
public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
    
    int c = ctl.get();
    // 当前工作线程数 < 核心线程数,调用addWorker,标记为核心线程
    if (workerCountOf(c) < corePoolSize) {
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }
   // 当前工作线程数 >= 核心线程数,将任务添加到等待队列
    if (isRunning(c) && workQueue.offer(command)) {
        int recheck = ctl.get();
        // 再次检测线程池状态,如果不为Running,删除已添加的任务
        if (! isRunning(recheck) && remove(command))
           // 执行拒绝策略
            reject(command);
       // 线程池处于RUNNING状态 或 线程池处于非RUNNING状态但是任务remove失败
        else if (workerCountOf(recheck) == 0)
          // 这行代码是为了SHUTDOWN状态下没有活动线程了,但是队列里还有任务没执行这种特殊情况
          // 添加一个null任务是因为SHUTDOWN状态下,线程池不再接受新任务,该方法会创建新的线程,从队列中获取任务并执行。
          // 清理队列中剩余的任务
           addWorker(null, false);
    }
   // 当前工作线程数 >= 核心线程数 且 等待队列已满,调用addWorker,标记为非核心线程
    else if (!addWorker(command, false))
        // 执行拒绝策略
        reject(command);
}

#addWorker

/**
 * 1. 当前线程工作数 +1
 * 2. 创建Worker,将worker与当前线程绑定
 * 3. 添加worker到workers,记录线程池达到的最大数量
 * 4. 执行worker#run
 */
private boolean addWorker(Runnable firstTask, boolean core) {
    retry:
    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);
​
      /*
       * 这条语句等价:rs >= SHUTDOWN && (rs != SHUTDOWN || firstTask != null || workQueue.isEmpty())
       * 满足下列条件则直接返回false,线程创建失败:
       *    rs > SHUTDOWN: STOP || TIDYING || TERMINATED 此时不再接受新的任务,且所有任务执行结束
       *    rs = SHUTDOWN: firtTask != null 此时不再接受任务,但是仍然会执行队列中的任务
       *    rs = SHUTDOWN: firtTask == null && workQueue.isEmpty() 见execute方法的addWorker(null, false)
       * 最后一种情况: SHUTDONW状态下,如果workQueue不为空继续往下执行
       * execute()只有workCount==0的时,addWorker(null, false),firstTask才会为null。
       * 也就是说线程池SHUTDOWN了不再接受新任务,但是此时workQueue队列不为空,那么还得创建线程把任务给执行完才行。
       */
        if (rs >= SHUTDOWN &&
            ! (rs == SHUTDOWN && firstTask == null && !workQueue.isEmpty())
           )
            return false;
​
      /* 执行到此:
       * 1)线程池状态为RUNNING
       * 2)线程池状态为SHUTDOWN,但是任务队列还有任务未执行
       */
        for (;;) {
            int wc = workerCountOf(c);
          // 如果当前线程工作数 >= 线程池最大容量,返回false,
          // 或者 如果当前线程是核心线程,大于核心线程数返回false,如果是非核心线程,大于创建时指定的最大线程数返回false 
            if (wc >= CAPACITY ||
                wc >= (core ? corePoolSize : maximumPoolSize))
                return false;
          // 当前线程工作数+1
            if (compareAndIncrementWorkerCount(c))
                break retry;
          // CAS自增失败,重新获取状态,如果线程状态发生改变退出循环,否则继续自旋
            c = ctl.get(); 
            if (runStateOf(c) != rs)
                continue retry;
        }
    }
​
    boolean workerStarted = false;
    boolean workerAdded = false;
    Worker w = null;
    try {
        // 创建worker,将worker与w.thread进行绑定 
        w = new Worker(firstTask);
        final Thread t = w.thread;
        if (t != null) {
            final ReentrantLock mainLock = this.mainLock;
​
            // 加锁
            mainLock.lock();
            try {
                // 重新检测线程池状态
                int rs = runStateOf(ctl.get());
                if (rs < SHUTDOWN ||
                    (rs == SHUTDOWN && firstTask == null)) {
                    // 如果线程还在执行中,则抛出异常。简单理解线程状态不是 NEW
                    if (t.isAlive()) 
                        throw new IllegalThreadStateException();
                    // 添加到worker集合,worker集合可以理解为真正的线程池
                    workers.add(w);
                    int s = workers.size();
                    // 记录线程池达到的最大数量
                    if (s > largestPoolSize)
                        largestPoolSize = s;
                    workerAdded = true;
                }
            } finally {
                // 解锁
                mainLock.unlock();
            }
            if (workerAdded) {
                // 执行Worker#run
                t.start();
                workerStarted = true;
            }
        }
    } finally {
        if (! workerStarted)
            // 添加失败,当前线程工作数 -1
            addWorkerFailed(w);
    }
    return workerStarted;
}

#runWorker

/*
 * 1. 先执行worker自带的task,执行完之后赋值为null,再从等待队列继续获取task,如果等待队列也没有task退出循环,结束线程
 * 2. task执行前,会通过worker#lock进行加锁,配置worker#tryLock,防止线程被中止
 */
final void runWorker(Worker w) {
    Thread wt = Thread.currentThread();
   // firstTask,未经历线程复用时的任务
    Runnable task = w.firstTask;
    w.firstTask = null;
   // 允许线程中断
    w.unlock(); 
    boolean completedAbruptly = true;
    try {
       // 如果task为null,则从等待队列继续获取task,实现线程复用
        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,准备下次循环从等待队列中继续获取task
                task = null;
                w.completedTasks++;
               // 解锁
                w.unlock();
            }
        }
        completedAbruptly = false;
    } finally {
        // 如果当前工作线程数 <  核心线程数,通过addWorker(null, false)创建worker,保持指定数量的核心线程存活
        processWorkerExit(w, completedAbruptly);
    }
}

#getTask

/**
 * 1. 根据当前线程数是否 大于 核心线程数判断,当前线程是阻塞获取还是等待获取
 */
private Runnable getTask() {
    boolean timedOut = false; // Did the last poll() time out?
​
    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);
​
        // 如果线程池状态 >= stop || 等待队列为空,当前工作线程数-1【待研究】
        if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
            decrementWorkerCount();
            return null;
        }
​
        int wc = workerCountOf(c);
​
        // 当前工作线程数 > 核心线程数,timed为true
        boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
​
       // 【待研究】
        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;
        }
    }
}

#submit

# 有返回值,返回值为FutureTask
Future<?> submit(Runnable task);
<T> Future<T> submit(Runnable task, T result);
<T> Future<T> submit(Callable<T> task);
​
参数为Runnable时执行流程:
AbstractExecutorService#submit 
  -> new FutureTask 
     -> new RunnableAdapter(RunnableAdapter 实现了Callable,实现了call)
  -> ThreadPoolExecutor#execute,参数为FutureTask
  -> new Worker -> Worker#run -> Worker#runWorker ->Worker.task(FutureTask)#run
  -> FutureTask#run -> Callable(RunnableAdapter)#call
  -> Runnable实现类#run,执行业务代码
    
  
参数为Callable时执行流程:
AbstractExecutorService#submit 
  -> new FutureTask 
  -> ThreadPoolExecutor#execute,参数为FutureTask
  -> new Worker -> Worker#run -> Worker#runWorker ->Worker.task(FutureTask)#run
  -> FutureTask#run
  -> Callable实现类#call,执行业务代码
  
​

Runnable、Callable、Future、FutureTask

Runnable
  • 线程启动参数
  • #run,无返回值,异常不会抛出(外部catch不到)
Callable
  • 间接作为线程启动参数,需要FutureTask配合
  • #call,有返回结果(Future类型 -> FutureTask),异常会抛出(外部可以catch到)
Future
  • 接口,代表异步计算结果
  • #get、#isDone、#cancel 等方法
FutureTask
  • 可以提供异步计算结果的任务。因为其实现RunnableFuture接口,而RunnableFuture接口继承了Runnable、Future接口
  • FutureTask可以用来包装 Runnable、Callable的实现类

适配器模式

FutureTask是Runnable的实现类,是Callable向Runnable的适配器,是类适配器方式

RunnableAdapter,Runnable转Callable,对象适配器实现

/**
 * RunnableAdapter对象持有Runnable的引用, 而RunnableAdapter又实现于Callable
 */
​
static final class RunnableAdapter<T> implements Callable<T> {
    final Runnable task;
    final T result;
    RunnableAdapter(Runnable task, T result) {
        this.task = task;
        this.result = result;
    }
    
    // 在Callable#call中,执行Runnable#run
    public T call() {
        task.run();
        return result;
    }
}   

问题

创建的核心线程会不会销毁
不会销毁:
​
在#runWorker的while循环中,getTask返回null,就会退出while循环,不在继续进行线程复用。
而#getTask方法,只有线程池当前工作线程数>核心线程数,且未从等待队列获取到task时,才会返回null,否则是会一直阻塞在workQueue#take方法。
Worker#runWorker,先执行w.unlock,允许线程中断什么意思
初始化Worker的时候会设置state-1,在执行#runWorkerw.unlock时候会将state设置为0,当获取到task后,设置state1;
​
#interruptIfStarted 会被#shutdownNow 调用到,这里有个判断,只有state >= 0时,才中断。
interruptIdleWorkers方法梳理,涉及到线程池中止、扩容等操作