Java线程池源码分析

概述

线程是稀缺资源,如果线程被无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,所以合理的使用线程池对线程进行统一分配、调优和监控,有巨大的好处。

  • 降低资源消耗
  • 提高系统响应速度
  • 提高线程可管理性

JDK1.5引入了Executor线程池框架,通过把任务的提交和执行进行解耦,我们只需要定义好任务(Runnable),然后将它提交给线程池,而不用关心该任务是如何执行、被哪个线程执行以及什么时候执行。

类结构

Java线程池相关类库全部位于java.util.concurrent包下,类结构如下图:
在这里插入图片描述

  • Executor : 是最顶层接口,它只包含一个方法execute()
  • ExecutorService : 继承自Executor接口,在Executor接口基础上添加了submit()(关于execute与submit区别,会在本文后边详细叙述)方法,并添加了若干线程池状态(关于线程池状态,会在本文后边详细叙述)操作方法,如shutdown(),shutdownNow()等。
  • AbstractExecutorService : 继承自ExecutorService,并实现了ExecutorService的若干方法,如submit()等。
  • ThreadPoolExecutor : 继承于AbstractExecutorService,是线程池的核心类,几乎所有与线程池有关的逻辑都封装在这个类里边。
  • DiscardPolicy、DiscardOldestPolicy、AbortPolicy、CallerRunsPolicy : 四种饱和策略。
  • Worker : 线程池真正的线程类,本身实现了Runnable接口和AQS(AbstractQueuedSynchronizer)接口。

详细解析

构造函数

总共有四个,分别为

//1
public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue)
//2
public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
//3                              ThreadFactory threadFactory)
public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              RejectedExecutionHandler handler)
//4
public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)

构造函数主要是对线程池参数的初始化,关于线程池参数可以参考另外一篇文章Java线程池参数解析。其中构造函数1-3最后都是调用到了构造函数4,简单分析一下4即可。

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
	    if (corePoolSize < 0 ||
	        maximumPoolSize <= 0 ||
	        maximumPoolSize < corePoolSize ||
	        keepAliveTime < 0)
	        throw new IllegalArgumentException();
	    if (workQueue == null || threadFactory == null || handler == null)
	        throw new NullPointerException();
	    this.corePoolSize = corePoolSize;
	    this.maximumPoolSize = maximumPoolSize;
	    this.workQueue = workQueue;
	    this.keepAliveTime = unit.toNanos(keepAliveTime);
	    this.threadFactory = threadFactory;
	    this.handler = handler;
}
  • 首先,对各个数值型参数做校验,校验规则为 : (1) corePoolSize < 0 (2) maximumPoolSize <=0 (3) maximumPoolSize < corePoolSize (4) keepAliveTime < 0,以上情况均抛出IllegalArgumentException异常。
  • 然后,对阻塞队列、线程工厂、饱和策略判空,任一项为空则抛出NullPointerException异常。
  • 最后,通过校验之后,将各个参数值赋值给ThreadPoolExecutor实例的相应成员变量。

一些成员变量

由于corePoolSize、maximumPoolSize等线程池参数已经在博客Java线程池参数解析有过叙述,故此处不再赘述。

private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));

ctl是线程池中一个非常重要的变量,以它的低29位表示线程池中处于RUNNING状态的线程个数,高3位表示线程池所处的状态(关于线程池的状态我们待会再讲)。

private static final int COUNT_BITS = Integer.SIZE - 3;

COUNT_BITS表示RUNNING状态下的线程数对应二进制的位数,也就是29。

private static final int CAPACITY   = (1 << COUNT_BITS) - 1;

CAPACITY用于与ctl做与运算,得到RUNNING状态下线程的个数。CAPACITY的值为

000111111111111111111111111111111
private static final int RUNNING    = -1 << COUNT_BITS;

RUNNING表示线程池的运行状态,可处理新任务并执行队列中的任务,十进制表示为-536870912。二进制表示为

11100000000000000000000000000000
private static final int SHUTDOWN   =  0 << COUNT_BITS;

SHOTDOWN表示线程池的关闭态,不接受新任务,但处理队列中的任务,值为0。

private static final int STOP       =  1 << COUNT_BITS;

STOP表示线程池的停止态,不接受新任务,不处理队列中任务,且打断运行中任务,十进制表示为536870912。二进制表示为

00100000000000000000000000000000
private static final int TIDYING    =  2 << COUNT_BITS;

TIDYING表示线程池的整理态,所有任务已经结束,workerCount = 0 ,将执行terminated()方法,值为1073741824。二进制表示为

01000000000000000000000000000000
private static final int TERMINATED =  3 << COUNT_BITS;

TERMINATED表示线程池的结束态,terminated() 方法已完成,值为1610612736。二进制表示为

01100000000000000000000000000000

不难发现,在所有的五种状态中SHUTDOWN值等于0,RUNNING值小于0,其他三种状态STOP、TIDYING、TERMINATED值均大于0。

private final HashSet<Worker> workers = new HashSet<Worker>();

workers用于存储真正运行的任务Worker(后边我们会详细讲述Worker的运行原理)。

private volatile boolean allowCoreThreadTimeOut;

allowCoreThreadTimeOut用于表示核心线程在空闲一定时间之后是否过期。

关于线程池状态

为了更好的管理线程,Java线程池总共包含五种状态。要注意的是,线程池的状态要与线程的状态区别开来,这两者之间没有什么必然的联系。具体请看下图
在这里插入图片描述

  • RUNNING : 运行态,也是线程池的默认状态,当new一个ThreadPoolExecutor实例之后,这个ThreadPoolExecutor的状态就是运行态。运行态能够接受新添加任务,也能够对阻塞队列中的任务进行处理。
  • SHOWDOWN : 关闭态,当调用ThreadPoolExecutor实例的showdown()方法之后,这个ThreadPoolExecutor实例就会进入关闭态。关闭态能够对阻塞队列中的任务进行处理,不能够接受新添加的非空任务,但是可以接受新添加的空任务。
  • STOP : 停止态,当调用ThreadPoolExecutor实例的shutdownNow()方法之后,这个ThreadPoolExecutor实例就会进入停止态。停止态不能接受新添加任务,也不能够对阻塞队列中的任务进行处理,并且会中断正在运行的任务。
  • TIDYING : 整理态,当线程池中所有任务已被终止, 这个ThreadPoolExecutor实例就会进入停止态。
  • TERMINATED : 结束态,当线程池处于整理态,并调用terminated()方法,执行完毕之后,就会进入结束态,此状态也表示整个线程池生命周期的结束。

了解线程池的五个状态,对于理解线程池的工作原理至关重要,它是基础中的基础,所以在读线程池源码前一定要了解一下它们。

添加一个任务之后发生了什么?

接下来,我们主要分析一下execute()方法,也就是添加一个Runnable任务之后,到底发生了什么?

execute()方法

public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        int c = ctl.get();
        if (workerCountOf(c) < corePoolSize) {
            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);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        else if (!addWorker(command, false))
            reject(command);
}

首先,对添加的任务(也就是代码里边的command参数)判空,若空,则抛出NullPointerException异常。
然后,拿到ctl的值(也就是线程池运行状态(高3位)和当前运行任务数(低29位))。
然后,判断当前运行任务数(workerCountOf(c ))是否小于核心线程数(corePoolSize),简单看一下workerCountOf(c )方法。

private static int workerCountOf(int c)  { 
	return c & CAPACITY;
}

CAPACITY我们在前边已经讲过,是低29位全1高3位全0,它与c做与运算得到的就是当前运行的线程个数。

然后执行addWorker()方法,具体请先看下文addWorker()方法
如果addWorker()成功,则直接return,结束execute。
如果addWorker()失败,则刷新c的值。

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);
}
else if (!addWorker(command, false))
    reject(command);

如果addWorker()失败,那么接下来的策略是将任务放入阻塞队列。
首先判断线程池状态是否为运行态isRunning©。
如果任务加入阻塞队列成功,即workQueue.offer(command)返回true。
接下来使用recheck做了一个二重检查,如果此时线程池已经处于非运行状态,则将任务remove掉。并且执行拒绝策略。

final void reject(Runnable command) {
 	handler.rejectedExecution(command, this);
}

如果阻塞队列添加任务失败,则根据coreSize<当前线程数<maxSize的策略添加Worker。
如果添加失败,则执行拒绝策略。

addWorker()方法

然后,调用addWorker(command, true)方法向线程池添加任务,并以返回值作为判断条件,若添加成功,方法结束,return。若添加失败,则执行c = ctl.get() 更新c的值。我们看一下addWorker(command, true)方法

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 &&
                ! (rs == SHUTDOWN &&
                   firstTask == null &&
                   ! workQueue.isEmpty()))
                return false;

            for (;;) {
                int wc = workerCountOf(c);
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;
                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);
            final Thread t = w.thread;
            if (t != null) {
                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());

                    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) {
                    t.start();
                    workerStarted = true;
                }
            }
        } finally {
            if (! workerStarted)
                addWorkerFailed(w);
        }
        return workerStarted;
}

先看第一部分

retry:
for (;;) {
    int c = ctl.get();
    int rs = runStateOf(c);

    // Check if queue empty only if necessary.
    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;
        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
    }
}

首先定义了一个标签retry:,这是break的语法糖,用于跳出二重循环,有兴趣的小朋友可以研究一下哈。
然后以一个for (;; ) 开始了外层死循环(此处为什么不用while(true)而是用for(;; ) ,请参考for(;;)和while(true)的区别)。

先看前半部分

int c = ctl.get();
int rs = runStateOf(c);

// Check if queue empty only if necessary.
if (rs >= SHUTDOWN &&
    ! (rs == SHUTDOWN &&
       firstTask == null &&
       ! workQueue.isEmpty()))
    return false;

变量c前边讲过,此处不赘述。变量rs表示的是什么呢?看一下runStateOf(c )方法实现

private static int runStateOf(int c)     { 
	return c & ~CAPACITY; 
}

由本文前边叙述我们知道CAPACITY值为

000111111111111111111111111111111

则~CAPACITY值为

11100000000000000000000000000000

c & ~CAPACITY则表示的是c的高三位表示的值,其实就是线程池的运行状态。

然后再看这段代码

if (rs >= SHUTDOWN &&
    ! (rs == SHUTDOWN &&
       firstTask == null &&
       ! workQueue.isEmpty()))
    return false;

这段代码有点绕,但是总得来分析可以发现,主要是围绕线程池的状态以及阻塞队列中的任务数来做的判断。具体如下

  • 第一个条件判断rs >= SHUTDOWN并且和后边一大堆做与运算,表达的意思其实就是:如果rs < SHUTDOWN,则不会return false,那么就会继续执行后边的逻辑。而rs < SHUTDOWN表达的含义是什么呢?前边说过,只有RUNNING状态值小于0,所以表达的含义为:如果线程池处于运行态,则不会return false。也就是说,如果线程池处于运行态,则可以添加任务。
  • 那如果rs >= SHUTDOWN,也就是说线程池并不是处于运行态呢?这个时候就要具体讨论了。! (rs == SHUTDOWN && firstTask == null && ! workQueue.isEmpty())) 为真,也就是rs == SHUTDOWN && firstTask == null && ! workQueue.isEmpty()) 为假的时候,return false,不添加任务。也就是说rs == SHUTDOWN && firstTask == null && ! workQueue.isEmpty())成立的时候,会添加任务。rs == SHUTDOWN && firstTask == null && ! workQueue.isEmpty()) 表达的含义是:线程池处于关闭态,并且添加的任务为空,并且阻塞队列非空同时成立。进一步来讲,就是说(1)如果线程池处于停止态,整理态,结束态,则不会添加任务;(2)如果线程池处于关闭态,但是任务不为空,不会添加任务;(3)如果线程池处于关闭态,任务为空,但是阻塞队列为空,也不会添加任务。再进一步来讲表达了两个含义(1)线程池如果处于关闭态:不会添加非空任务 (2) 线程池如果处于关闭态:可以在阻塞队列非空的情况下添加空任务。为什么这么做呢,因为如果阻塞队列为空,整个线程池不会再新建线程且不会再往队列添加新任务,所以没必要在添加空任务。但是如果阻塞队列不为空,有可能已经没有线程,关闭态的线程池需要把阻塞队列的任务消费完成,所以需要新建线程消费任务,添加一个空任务的目的就是为了新建一个新线程消费阻塞队列中的任务。

简单来讲,这段代码就是根据线程池状态以及阻塞队列是否为空,来判断是否需要添加新任务。

然后看后半部分代码

for (;;) {
    int wc = workerCountOf(c);
    if (wc >= CAPACITY ||
        wc >= (core ? corePoolSize : maximumPoolSize))
        return false;
    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
}

此处也用了一个死循环。首先看wc变量,它表示当前线程池中正在运行的线程个数(前边讲过这个方法)。
先看第一个if判断

if (wc >= CAPACITY ||
        wc >= (core ? corePoolSize : maximumPoolSize))
        return false;
  • 如果wc >= CAPACITY,也就是运行线程个数大于等于线程池所能容纳的最大线程个数,return false,结束addWorker()方法。
  • 如果wc < CAPACITY,判断wc 与 corePoolSize 或 maximumPoolSize大小,此处core表示的是是否跟核心线程个数比较,如果core为true 且 wc >=corePoolSize,则return false结束addWorker()方法,如果core为false 且 wc >=maximumPoolSize,则return false结束addWorker()方法。

然后看第二个if判断

if (compareAndIncrementWorkerCount(c))
        break retry;

如果compareAndIncrementWorkerCount(c )为真,则跳出外层死循环。看下compareAndIncrementWorkerCount(c )实现

private boolean compareAndIncrementWorkerCount(int expect) {
    return ctl.compareAndSet(expect, expect + 1);
}

ctl是AtomicInteger类型变量,此处采用了CAS操作保证了ctl自增的线程安全性。
如果compareAndIncrementWorkerCount(c )为假,说明ctl自增失败,原因有可能是其他线程做了自增操作。
所以需要更新变量c的值,并继续执行内层死循环做ctl自增操作。
但是在继续执行内层死循环之前,要先判断线程池的运行状态是否发生了变化,例如从RUNNING变成了STOP,则不能继续执行内层死循环,而是执行外层死循环,重新做状态判断。代码如下

if (runStateOf(c) != rs)
        continue retry;

如果外层死循环执行结束,并且没有return false,那说明ctl自增操作成功。接下来开始添加新任务

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();
        try {
            // Recheck while holding lock.
            // Back out on ThreadFactory failure or if
            // shut down before lock acquired.
            int rs = runStateOf(ctl.get());

            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) {
            t.start();
            workerStarted = true;
        }
    }
} finally {
    if (! workerStarted)
        addWorkerFailed(w);
}
return workerStarted;

首先定义了两个boolean类型变量workerStarted表示线程是否已启动,workerAdded表示线程是否已经添加到线程池。Worker类型变量w表示此次要添加的线程,初始化为null。
接下来对代码添加异常检测try-finally,这个待会再说。首先看try块内代码。

w = new Worker(firstTask);

看到这,有必要了解一下Worker实例的初始化过程都做了哪些工作,请先看下文Worker实例初始化详细过程,然后在回到此处继续看。

接着,获取到了线程t,并对t判空。
然后获取全局可重入锁,并加锁

final ReentrantLock mainLock = this.mainLock;
mainLock.lock();

接着,又加了一个try-finally,这个try没什么特殊含义,唯一的功能是释放可重入锁。
然后执行如下代码

int rs = runStateOf(ctl.get());
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;
 }

首先获取线程池运行状态rs,然后根据rs做逻辑判断。
如果线程池处于运行态或者处于关闭态但提交任务为空,则可以做添加线程操作。
判断线程是否已经启动,如果已经启动,抛出IllegalThreadStateException异常(此处为什么要检查线程状态,一直很费解,有理解的同学可以留言告知,谢谢)。
将Worker实例加入线程池workers。

int s = workers.size();
if (s > largestPoolSize)
    largestPoolSize = s;

largestPoolSize变量用于记录出现过的最大线程数。
置workerAdded变量为true,表示已经创建线程,并添加到了线程池。

然后执行如下代码

if (workerAdded) {
    t.start();
    workerStarted = true;
}

如果线程已经被加入线程池,则启动线程,并置标志位workerStarted为true,表示线程已经启动。

最后执行

if (! workerStarted)
    addWorkerFailed(w);

如果线程没有启动成功,执行addWorkerFailed()开启回滚操作,具体请看下文 addWorkerFailed() 详细过程。

Worker实例添加成功之后。由于线程池把Worker作为线程来运行,所以有必要阅读一下Worker的run()方法,具体请看下文 Worker的run()方法 详细过程。。

Worker的run()方法

public void run() {
    runWorker(this);
}

继续看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 ((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);
    }
}

首先

Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts

获取当前线程wt,提交的任务task,并置w的firstTask为空。
然后w解锁。w.unlock()这行代码与之前w的构造函数的setState(-1)相对应。
接下来执行

while (task != null || (task = getTask()) != null)

如果提交的任务不为空,则处理提交的任务,如果提交的任务为空,则通过getTask()从阻塞队列获取任务。
我们先看一下 ,getTask()方法实现,具体请看下文 getTask()方法 详细过程。。

我们接着看。

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

首先加全局锁,细节不管,最后执行

task.run();

相当于调用了我们提交的Runnable的run方法。
w.completedTasks++;用于计算所有已完成任务。

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.
        if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
            decrementWorkerCount();
            return null;
        }

        int wc = workerCountOf(c);

        // Are workers subject to culling?
        boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

        if ((wc > maximumPoolSize || (timed && timedOut))
            && (wc > 1 || workQueue.isEmpty())) {
            if (compareAndDecrementWorkerCount(c))
                return null;
            continue;
        }

        try {
            Runnable r = timed ?
                workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                workQueue.take();
            if (r != null)
                return r;
            timedOut = true;
        } catch (InterruptedException retry) {
            timedOut = false;
        }
    }
}

首先

boolean timedOut = false;

定义timedOut变量表示当前线程是否已经过期。

然后接一个死循环

for (;;)

然后

int c = ctl.get();
int rs = runStateOf(c);

获取到c和线程池状态。
然后

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

这个if的含义为 : 如果线程池处于STOP、TIDYING、TERMINATED三种状态之一,或者处于SHUTDOWN状态且阻塞队列为空时,执行decrementWorkerCount(),并返回空任务。

如果不是上述情景,则继续执行

int wc = workerCountOf(c);
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

获取当前运行的线程个数。
timed变量表示当前线程从阻塞队列获取Runnable时,是否执行过期这种操作,主要分为两种情况:1、是否允许核心线程过期;2、当前运行线程个数是否大于核心线程阈值。

然后

if ((wc > maximumPoolSize || (timed && timedOut))
	   && (wc > 1 || workQueue.isEmpty())) {
	   if (compareAndDecrementWorkerCount(c))
	       return null;
	   continue;
}

相当于如果满足wc > maximumPoolSize || (timed && timedOut)) && (wc > 1 || workQueue.isEmpty()),则将当前运行线程数减一,如果减一成功,返回null。如果减一失败,则继续往下执行。

try {
    Runnable r = timed ?
        workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
        workQueue.take();
    if (r != null)
        return r;
    timedOut = true;
} catch (InterruptedException retry) {
    timedOut = false;
}

首先根据是否执行过期策略(timed),以不同的方式(poll和take)从阻塞队列获取Runnable,如果获取任务r非空,则返回r。如果获取任务为空,则说明已经到了过期时间,timedOut = true,那么在下一次循环时,线程数减一,退出方法。

Worker实例初始化

首先对w进行了初始化。我们首先看一下w的构造过程,以及Worker的类型。

private final class Worker
        extends AbstractQueuedSynchronizer
        implements Runnable
{
    final Thread thread;
    Runnable firstTask;
    volatile long completedTasks;

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

    /** Delegates main run loop to outer runWorker  */
    public void run() {
        runWorker(this);
    }
}

介于篇幅限制,此处只展示了部分代码。
我们发现,Worker实现了Runnable接口,表明Worker是一个作为线程来运行的。并且Worker继承了AbstractQueuedSynchronizer(AQS),关于AQS,我们在另外一个地方会有详细讨论,此处AQS主要用于终止工作中的线程。
首先,执行

setState(-1);

相当于调用父类AbstractQueuedSynchronizer的setState(int newState)方法

protected final void setState(int newState) {
   state = newState;
}

即 将state值设置为-1,原因是防止线程被中断。
然后执行

this.firstTask = firstTask;

对成员变量firstTask赋值。此处参数值firstTask表示刚刚提交过来的Runnable任务,因为这个Worker线程以后有可能会消费阻塞队列中的任务,所以刚刚提交的任务被称为第一个任务。。
然后执行

this.thread = getThreadFactory().newThread(this);

注意 : 此处的入参是this,也就是当前Worker对象,即上文中的w对象。
再看一下newThread()方法,此处getThreadFactory()默认实例化DefaultThreadFactory对象(为什么是DefaultThreadFactory,请追踪构造方法)。newThread()代码如下

public Thread newThread(Runnable r) {
    Thread t = new Thread(group, r,
                          namePrefix + threadNumber.getAndIncrement(),
                          0);
    if (t.isDaemon())
        t.setDaemon(false);
    if (t.getPriority() != Thread.NORM_PRIORITY)
        t.setPriority(Thread.NORM_PRIORITY);
    return t;
}

乖乖,你发现了什么?线程t竟然不是通过firstTask这个Runnable来构造的,而是通过Worker对象w来构造的。为什么这么设计呢?原因很简单,假如以firstTask来建立线程的话,那以后从阻塞队列再消费任务的时候,是不是读一个任务建一个线程呢?这样做的话,那也就失去了线程池的意义了啊。而已Worker实例来建立线程的话,完全可以在Worker线程的run()方法内调用任务的run()方法,实现线程的复用,实际上,线程池的研发人员就是这么做的。

讲到这,Worker实例w已经构造结束。

addWorkerFailed()

private void addWorkerFailed(Worker w) {
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        if (w != null)
            workers.remove(w);
        decrementWorkerCount();
        tryTerminate();
    } finally {
        mainLock.unlock();
    }
}

首先使用mainLock加锁。
然后,如果w不为空的话,从集合中remove掉该w。
接着,执行decrementWorkerCount()方法,decrementWorkerCount实现

 private void decrementWorkerCount() {
    do {

	} while (! compareAndDecrementWorkerCount(ctl.get()));
 }

这是一个死循环,当compareAndDecrementWorkerCount(ctl.get())为真的时候,才会褪出。看一下compareAndDecrementWorkerCount(ctl.get())方法实现

private boolean compareAndDecrementWorkerCount(int expect) {
    return ctl.compareAndSet(expect, expect - 1);
}

很明显,这是一个CAS操作,上边的do-while相当于自旋实现了一个CAS操作,最终实现ctl减一操作。

最后执行tryTerminate();tryTerminate()此处不细讲,有兴趣的小伙伴可以自行阅读源码哦!

下午接着写吧,先发出来,哈哈

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 游动-白 设计师:白松林 返回首页
实付 9.90元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值