Java线程池ThreadPoolExecutor源码解析

Java中的线程池相信大家都很熟悉,不熟悉的朋友可以看我的另一篇博文Java线程池类型以及execute和submit方法的区别。本文主要针对线程池核心类ThreadPoolExecutor中的常用重要方法进行源码解析。

ThreadPoolExecutor中代表线程池状态的属性

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;

/**
* 获取线程池状态
*/
private static int runStateOf(int c)     { return c & ~CAPACITY; }

/**
* 获取线程池中的线程数量
*/
private static int workerCountOf(int c)  { return c & CAPACITY; }

private static int ctlOf(int rs, int wc) { return rs | wc; }
  • ctl属性作为AtomicInteger类存放了类中的两种信息。在其中由高3位来保存线程池的状态,后29位来保存此时线程池中的Woker类线程数量。因此在后面给出的runStateOf()和workerCountOf()方法分别是查看线程状态和线程数量的方法。

  • RUNNING状态说明正在执行队列中的任务,同时也可以接受新添加的任务

  • SHUTDOWN状态不会接受新添加的任务,但是仍然会处理队列中未完成的任务

  • STOP状态不会接受新添加的任务,也不会处理队列中的任务,而正在执行的任务也会被打断

  • TIDYING状态标识着所有的任务已经终止,线程池中的Worker线程为0。也就是STOP状态在清理完所有线程之后就会进入该状态,同时在SHUTDOWN状态中队列为空以及线程清理完毕之后也会直接进入这个状态,在这个阶段会循环执行terminated()方法

  • TERMINATED状态是线程池最后的状态。在执行完terminated()方法后,就会进入改状态,说明该线程池已经完全停止

ThreadPoolExecutor中代表线程池基本信息的属性

// 标识线程池中允许存活最少的核心线程数量。但是需要注意的是,如果allowCoreThreadTimeOut设置为true(默认为false),那么所有空闲线程(核心和非核心线程)的存活时间只有keepAliveTime。也就是说,当allowCoreThreadTimeOut为true时候,线程池最小的线程数量为0
private volatile int corePoolSize;

// 记录线程池中存在过的最大线程数量
private int largestPoolSize;

// 代表线程池中最大的线程数量
private volatile int maximumPoolSize;

// 记录已完成的任务总数
private long completedTaskCount;

// 若allowCoreThreadTimeOut为true,则池中所有空闲线程(包括核心线程)的最大等待时间
// 若allowCoreThreadTimeOut为false,池中超过corePoolSize数量的空闲线程(非核心线程)的最大等待时间
// 空闲超过最大等待时间则销毁
private volatile long keepAliveTime;

// 是否允许启用核心线程最大等待时间。false为不启用,则空闲的核心线程不会被销毁
private volatile boolean allowCoreThreadTimeOut;

// 存放任务的工作队列
private final BlockingQueue<Runnable> workQueue;

// 存放线程的Set集合
private final HashSet<Worker> workers = new HashSet<Worker>();

// 可重入锁
private final ReentrantLock mainLock = new ReentrantLock();

// 可重入锁的Condition队列
private final Condition termination = mainLock.newCondition();

// 创建线程的工厂
private volatile ThreadFactory threadFactory;

// 作为线程池中在不能接受任务的时候的拒绝策略
private volatile RejectedExecutionHandler handler;

Worker内部类

/**
* 可以看到Worker类继承了AbstractQueuedSynchronizer(AQS)类,而类中大部分的方法都是直接重写或者调用AQS中的方法
* 同时还实现了Runnable接口,可以将Worker的实例对象看作是一个线程
* 不熟悉的AQS的朋友建议先去了解下,再来了解这个Worker
*/
private final class Worker extends AbstractQueuedSynchronizer implements Runnable
{
    private static final long serialVersionUID = 6138294804551838833L;
	// 要运行的线程
    final Thread thread;
	// 要执行的任务
    Runnable firstTask;
    // 完成的任务数量
    volatile long completedTasks;

    /**
     * 构造方法
     */
    Worker(Runnable firstTask) {
        setState(-1);
        this.firstTask = firstTask;
        this.thread = getThreadFactory().newThread(this); // threadFactory创建线程
    }

    /**
    * 将运行线程任务工作委托给外部类ThreadPoolExecutor的runWorker方法
    */
    public void run() {
        runWorker(this);
    }

    /**
    * 0表示解锁状态
    * 1表示锁定状态。
    */
    protected boolean isHeldExclusively() {
        return getState() != 0;
    }

    /**
    * 通尝试获取锁(只是通过CAS操作改变状态,并没有涉及到唤醒阻塞线程的操作)
    */
    protected boolean tryAcquire(int unused) {
        if (compareAndSetState(0, 1)) {
            setExclusiveOwnerThread(Thread.currentThread());
            return true;
        }
        return false;
    }

    /**
    * 尝试释放锁(只是改变状态,并没有涉及到唤醒阻塞线程的操作)
    */
    protected boolean tryRelease(int unused) {
        setExclusiveOwnerThread(null);
        setState(0);
        return true;
    }
    
    /**
    * 获取锁
    */
    public void lock()        { acquire(1); }
    
    /**
    * 尝试获取锁
    */
    public boolean tryLock()  { return tryAcquire(1); }

	/**
    * 释放锁
    */
    public void unlock()      { release(1); }

	/**
    * 线程是否处于锁定状态
    */
    public boolean isLocked() { return isHeldExclusively(); }

	/**
    * 中断已经开始执行任务的线程
    */
    void interruptIfStarted() {
        Thread t;
        if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
            try {
                t.interrupt();
            } catch (SecurityException ignore) {
            }
        }
    }
}

了解完ThreadPoolExecutor中主要的内部属性和结构,接下来就针对线程池最常用的,也是最核心的方法进行源码讲解分析。

execute()

public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
    int c = ctl.get();
    if (workerCountOf(c) < corePoolSize) { // 池中线程数小于corePoolSize,则添加新的线程
        if (addWorker(command, true)) // 添加自带command任务的新线程
            return;
        c = ctl.get();
    }
    // 池中线程数量大于等于corePoolSize,或者添加线程失败,先查看线程池状态
    if (isRunning(c) && workQueue.offer(command)) { // 处于运行状态,则添加新的任务command进入任务队列
        int recheck = ctl.get();
		// 双重保险,再次查看线程池状态
        if (! isRunning(recheck) && remove(command)) // 不处于运行状态,则移除刚添加进任务队列的新任务command
            reject(command); // 拒绝执行command任务
        else if (workerCountOf(recheck) == 0) // 池中线程数量为0
            addWorker(null, false); // 添加新的空任务线程
    }
    else if (!addWorker(command, false)) // 不处于运行状态,或者添加任务进队列失败,则添加自带command任务的新线程
        reject(command); // 添加线程失败,拒绝执行command任务
}
  • addWorker()方法添加新线程:
private boolean addWorker(Runnable firstTask, boolean core) {
    retry:
    for (;;) { // 外部自旋
        int c = ctl.get();
        int rs = runStateOf(c);
		
        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)) // 采用CAS操作,对池中线程数量加1
                break retry; // 加1成功,则打破内外部自旋
            c = ctl.get();
            if (runStateOf(c) != rs) // 在内部自旋过程中,线程状态已改变,则重新执行外部自旋
                continue retry;
        }
    }

    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 {
                int rs = runStateOf(ctl.get());
                if (rs < SHUTDOWN ||
                    (rs == SHUTDOWN && firstTask == null)) { // 再次检查线程池状态,处于运行状态,或者SHUTDOWN状态而且任务为空
                    if (t.isAlive()) // 线程已启动,抛出异常
                        throw new IllegalThreadStateException();
                    workers.add(w); // 添加新线程进入线程集合
                    int s = workers.size();
                    if (s > largestPoolSize)
                        largestPoolSize = s;
                    workerAdded = true; // 标识添加线程成功
                }
            } finally {
                mainLock.unlock(); // 释放锁
            }
            if (workerAdded) { // 添加线程成功
                t.start(); // 启动线程,执行t线程中的run方法
                workerStarted = true; // 标识该线程已启动
            }
        }
    } finally {
        if (! workerStarted) // 线程启动失败
            addWorkerFailed(w); // 从线程集合中删除新添加的线程,相当于回滚
    }
    return workerStarted;
}
  • new Worker(firstTask)构造方法新建线程:
Worker(Runnable firstTask) {
    setState(-1);
    this.firstTask = firstTask;
    this.thread = getThreadFactory().newThread(this); // 将Worker实例对象run方法作为线程执行的任务
}

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;
}
  • addWorkerFailed()方法回滚操作:
private void addWorkerFailed(Worker w) {
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        if (w != null)
            workers.remove(w); // 删除已添加的线程
        decrementWorkerCount(); // 池中线程数量减一
        tryTerminate(); // 尝试将线程池状态转换为TERMINATED。(转换成功的提前是:线程池为SHUTDOWN或者STOP,而且池中的线程和任务队列都已清空)
    } finally {TER
        mainLock.unlock();
    }
}

了解了往线程池中添加线程的过程,我们再来看,线程池中是如何调用线程去执行任务的。

  • run()方法将运行线程任务工作委托给外部的runWorker方法去执行:
public void run() {
    runWorker(this);
}

final void runWorker(Worker w) {
    Thread wt = Thread.currentThread(); // 当前线程
    Runnable task = w.firstTask; // w线程本身自带的任务
    w.firstTask = null;
    w.unlock(); // 设置state为0、以及占用锁的线程为空,允许中断(注意,unlock方法已被重写,并不是执行AQS类中的释放唤醒线程的方法)
    boolean completedAbruptly = true; // 标识任务是否因为异常而终止执行,默认为是
    try {
        while (task != null || (task = getTask()) != null) { // 若线程本身自带的任务不为空,则执行该任务;否则,从任务队列中获取任务执行(线程在此while循环中不断获取并执行任务)
            w.lock(); // 设置state为1,以及设置占用锁的线程为当前线程(注意,lock方法已被重写)
            if ((runStateAtLeast(ctl.get(), STOP) ||
                 (Thread.interrupted() &&
                  runStateAtLeast(ctl.get(), STOP))) &&
                !wt.isInterrupted()) // 线程池状态处于TIDYING或者TERMINATED状态,而且当前线程未被中断
                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; // 任务完成,赋值为空,跳出while循环
                w.completedTasks++; // 该线程完成任务数量加1
                w.unlock();
            }
        }
        completedAbruptly = false; // 更新标识,执行任务期间没有异常
    } finally {
        processWorkerExit(w, completedAbruptly); // while循环结束,工作线程没有获取到任务,说明线程池已经处于非运行状态,或者工作线程等待超时,则销毁工作线程
    }
}
  • getTask()方法从任务队列中获取任务:
private Runnable getTask() {
    boolean timedOut = false;
    for (;;) { // 自旋
        int c = ctl.get();
        int rs = runStateOf(c);
        if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) { // 线程池处于非RUNNING状态,而且任务队列为空(即没有要执行的任务)
            decrementWorkerCount(); // 池中线程数量减1
            return null;
        }
        int wc = workerCountOf(c);
        boolean timed = allowCoreThreadTimeOut || wc > corePoolSize; // 若为true,说明allowCoreThreadTimeOut为true,或者池中线程数量大于核心线程数量;否则为false
        if ((wc > maximumPoolSize || (timed && timedOut))
            && (wc > 1 || workQueue.isEmpty())) { // 主要从自旋的超时等待进行判断
            if (compareAndDecrementWorkerCount(c)) // 线程空闲超时,池中线程数量减1,并在之后的方法中销毁
                return null;
            continue;
        }

        try {
            Runnable r = timed ?
                workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : // 需要限制线程最大空闲时间,如果超过时间仍然获取不到任务,则获取到的任务为空
                workQueue.take(); // 不需要限制线程最大空闲时间,无论如何都要获取到任务
            if (r != null) 
                return r; // 获取到任务后返回
            timedOut = true; // 没有获取到任务,设置等待超时为true
        } catch (InterruptedException retry) {
            timedOut = false;
        }
    }
}
  • processWorkerExit()方法销毁线程:
private void processWorkerExit(Worker w, boolean completedAbruptly) {
    if (completedAbruptly) // w线程中的任务执行异常
        decrementWorkerCount(); // 池中线程数减1
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        completedTaskCount += w.completedTasks;
        workers.remove(w); // 从线程集合中删除w线程(销毁w线程)
    } finally {
        mainLock.unlock();
    }
    tryTerminate(); // 尝试将线程池的状态转换为TERMINATED
    int c = ctl.get();
    if (runStateLessThan(c, STOP)) { // 线程池处于RUNNING或者SHUTDOWN状态
        if (!completedAbruptly) { // w线程正常执行完成任务
            int min = allowCoreThreadTimeOut ? 0 : corePoolSize; // 判断是否设置allowCoreThreadTimeOut。若为true则说明,线程池中最小空闲线程数量为0,否则为corePoolSize
            if (min == 0 && ! workQueue.isEmpty()) // min为0,而且任务队列不为空(仍然存在等待执行的任务)
                min = 1; // min设置为1(至少保留一个线程去执行等待中的任务)
            if (workerCountOf(c) >= min) // 池中线程数量大于min
                return; // 直接返回
        }
        addWorker(null, false); // 池中线程数量小于min,则添加新的空任务线程
    }
}

到此,关于线程池的添加线程,以及其中调用线程执行任务的源码分析结束了。
但本文内容仍未结束,因为线程池启动了,总是要关的。

shutdown()

/**
 * 有序关闭线程池。该过程中会中断池中的空闲线程,不会影响正在执行的线程,以及已经提交并存在于任务队列中的任务仍然会执行,但是不会接受任何新任务
*/
public void shutdown() {
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        checkShutdownAccess(); // 检查是否拥有权限关闭每个线程
        advanceRunState(SHUTDOWN); // 将线程池的状态转换为SHUTDOWN
        interruptIdleWorkers(); // 将池中的空闲线程全部中断
        onShutdown(); // 主要用于ScheduledThreadPoolExecutor用于取消延迟的任务,其他类型线程池该方法无内容
    } finally {
        mainLock.unlock();
    }
    tryTerminate(); // 尝试将线程池状态转换为TERMINATED
}

shutdownNow()

/**
 * 立即关闭线程池。池中所有的线程都会被中断,包括正在执行的线程,已经提交的任务不会处理,也不会接受任何新任务
*/
public List<Runnable> shutdownNow() {
    List<Runnable> tasks;
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        checkShutdownAccess(); // 检查是否拥有权限关闭每个线程
        advanceRunState(STOP); // 将线程池的状态转换为STOP
        interruptWorkers(); // 中断所有线程
        tasks = drainQueue(); // 排空任务队列,并返回任务列表
    } finally {
        mainLock.unlock();
    }
    tryTerminate(); // 尝试将线程池状态转换为TERMINATED
    return tasks;
}
  • drainQueue()方法排空任务队列,并返回任务列表:
private List<Runnable> drainQueue() {
    BlockingQueue<Runnable> q = workQueue;
    ArrayList<Runnable> taskList = new ArrayList<Runnable>();
    q.drainTo(taskList); // 将任务队列中的任务全部移出到taskList中
    if (!q.isEmpty()) { // 队列是DelayQueue或任何其他类型的队列,而poll或drainTo可能无法删除某些元素,则会将它们逐个删除,同时添加进入taskList
        for (Runnable r : q.toArray(new Runnable[0])) {
            if (q.remove(r))
                taskList.add(r);
        }
    }
    return taskList;
}

到此,Java线程池ThreadPoolExecutor源码解析终于结束。感谢阅读。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值