多线程-线程池源码

简介

这里了解ThreadPoolExecutor的工作机制

ThreadPoolExecutor的继承结构

  • Executor:线程池的顶层接口,定义了提交异步任务的方法
void execute(Runnable command);
  • ExecutorService:继承Executor,定义了关闭线程池、查看线程池是否关闭、提交有返回值的异步任务、批量提交异步任务的功能
public interface ExecutorService extends Executor {
    // 关闭线程池
    void shutdown();  // 等到任务执行完成后关闭
    List<Runnable> shutdownNow();  // 立刻关闭

    // 判断线程池是否关闭
    boolean isShutdown();
    boolean isTerminated();
    boolean awaitTermination(long timeout, TimeUnit unit)
        throws InterruptedException;

    // 提交一个有返回值的异步任务
    <T> Future<T> submit(Callable<T> task);
    <T> Future<T> submit(Runnable task, T result);
    Future<?> submit(Runnable task);

    // 批量提交异步任务
    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) // 返回所有异步任务的future
        throws InterruptedException;
    <T> T invokeAny(Collection<? extends Callable<T>> tasks)  // 如果有一个异步任务执行完成,立刻返回
        throws InterruptedException, ExecutionException;
}
  • AbstractExecutorService:没有新的抽象方法,部分实现了ExecutorService中的方法,主要是批量提交异步任务、提交有返回值的异步任务
public abstract class AbstractExecutorService implements ExecutorService {
  • ThreadPoolExecutor:继承了AbstractExecutorService,线程池的核心类,定义了异步任务在线程池中如何被执行,也就是线程池的工作机制
public class ThreadPoolExecutor extends AbstractExecutorService {

总结:

  • 线程池的顶层接口是Executor,Executor中定义了提交异步任务的方法,也就是execute方法,不过它只可以提交没有返回值的异步任务。
  • Executor的直接子类,ExecutorService,进一步丰富了线程池的功能,定义了submit方法,可以提交有返回值的异步任务的方法,定义关闭线程池的功能。
  • AbstractExecutorService中部分实现了ExecutorService中的功能,主要是批量提交异步任务、提交有返回值的异步任务。
  • ThreadPoolExecutor实现了核心功能

提交任务的方法

submit方法:它的内部是调用了execute方法,同时将异步任务封装到FutureTask中,然后调用FutureTask来获取返回值

// ThreadPoolExecutor中的submit方法继承自AbstractExecutorService类中,它是ThreadPoolExecutor的直接父类
public Future<?> submit(Runnable task) {
    // 如果任务对象为null,抛出空指针异常
    if (task == null) 
        throw new NullPointerException();
    // 创建一个新的FutureTask对象
    RunnableFuture<Void> ftask = newTaskFor(task, null);
    // 执行futureTask对象
    execute(ftask);
    // 返回futureTask对象
    return ftask;
}

// newTaskFor方法,在submit方法中被调用,参数runnable是要执行的任务,参数value是默认的返回值
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
    return new FutureTask<T>(runnable, value);
}

execute方法是执行异步任务的核心方法

public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
    // 获取线程池状态
    int c = ctl.get();
    // 1. 如果当前线程小于核心线程数,创建新线程来执行任务
    if (workerCountOf(c) < corePoolSize) {
        // addWorker方法,创建新线程并且执行任务
        if (addWorker(command, true))
            return;
        // 如果创建线程失败,重新获取线程池状态
        c = ctl.get();
    }
    // 2. 把任务添加到工作队列中,需要先判断线程池是不是正在运行
    if (isRunning(c) && workQueue.offer(command)) {
        int recheck = ctl.get();
        // 如果添加成功,再次检查线程池的状态,如果不是正在运行,从对列中移除任务,然后执行拒绝策略
        if (! isRunning(recheck) && remove(command))
            reject(command);
        // 3. 添加新的线程执行任务
        else if (workerCountOf(recheck) == 0)
            addWorker(null, false);
    }
    // 4. 线程池不是正常运行或者添加到同步队列失败,尝试创建新的线程来执行任务
    else if (!addWorker(command, false))
        // 创建线程失败,执行拒绝策略
        reject(command);
}

这个方法整体描述了线程池的工作机制,要注意的是,线程池的每个操作之前,都会先判断线程池的状态,如果在线程池的执行过程中用户关闭了线程池,线程池就不会再现阻塞队列中添加任务、或者是新建线程来处理任务。

线程池的状态

ThreadPoolExecutor使用一个int类型的数字来存储线程池的状态,int变量中的前3位是线程池的状态,后29位是线程池中线程的数量。这个int类型的数字被放在一个原子类中。

线程池的状态枚举:

  • RUNNING:线程池处于运行状态,可以接受新任务并处理队列中的任务。
  • SHUTDOWN:调用shutdown()方法时,线程池会从RUNNING转换到SHUTDOWN。表示线程池已关闭,不再接受新任务,但会继续处理已提交的任务。
  • STOP:线程池已停止,不再接受新任务,也不再处理队列中的任务。调用shutdownNow()方法时,线程池会从RUNNING或 SHUTDOWN状态转换到STOP状态。
  • TIDYING:线程池中的所有任务都已完成,线程池即将进入TERMINATED状态。
  • TERMINATED:线程池已完全终止,所有任务都已完成,线程池已关闭。

状态、容量相关的常量:

// 有效位数:29位,这里表示,一个int类型的数字,前3为存储状态,后29为存储线程数
private static final int COUNT_BITS = Integer.SIZE - 3; // Integer.SIZE是32,COUNT_BITS的值是29

/* 表示状态的常量,注意看二进制数的前三位 */
private static final int RUNNING    = -1 << COUNT_BITS;  // 11100000000000000000000000000000
private static final int SHUTDOWN   =  0 << COUNT_BITS;  // 00000000000000000000000000000000
private static final int STOP       =  1 << COUNT_BITS;  // 00100000000000000000000000000000
private static final int TIDYING    =  2 << COUNT_BITS;  // 01000000000000000000000000000000
private static final int TERMINATED =  3 << COUNT_BITS;  // 01100000000000000000000000000000

// 容量:1左移29位,相当于1的29次方,1在二进制中移到第30位,然后再减1,得出的数字,在二进制中,除了前三位,后面的都是1
private static final int CAPACITY   = (1 << COUNT_BITS) - 1;  // 00011111111111111111111111111111

// ctlOf方法:两个int类型的数字按位或,遇1则1
private static int ctlOf(int rs, int wc) { return rs | wc; }

状态是如何计算的:

// 1、状态的初始化:线程池的状态和线程数被存储在AtomicInteger类型的实例中。
// RUNNING和0按位或,遇1则1,它是将RUNNING设置到存储状态和数目的变量中。
// 线程池实例一旦被创建,就是运行态
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));

// 2、获取线程池的状态:参数c是AtomicInteger中存储的int类型的值,它和CAPACITY取反后的数进行按位与运算,遇0则0,
// CAPACITY取反后后29位变成0,前3为变成1,也就是保留参数c的前3位,这3位中存储的就是状态
private static int runStateOf(int c)     { return c & ~CAPACITY; }

// 3、状态转换是怎么操作的?通过advanceRunState方法,参数targetState是状态常量,例如SHUTDOWN
private void advanceRunState(int targetState) {
    // 循环操作,直到状态转换成功
    for (;;) {
        int c = ctl.get();
        if (runStateAtLeast(c, targetState) ||
            // 目标状态和线程数按位或,然后使用它的结果替换原来的状态,ctlOf是两个数字按位或,workerCountOf是计算线程数
            ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c))))
            break;
    }
}

线程数是如何计算的:

// 1、获取线程池中的线程数:参数c是AtomicInteger中存储的int类型的值,它和CAPACITY进行按位与运算,遇0则0,
// 因为CAPACITY的后29位都是1,前3位是0,所以是保留参数c的后29位,这29位中存储的就是线程数
private static int workerCountOf(int c)  { return c & CAPACITY; }

// 2、线程数加1是怎么操作的:通过cas算法,直接在AtomicInteger中存储的int数上加1
private boolean compareAndIncrementWorkerCount(int expect) {
    return ctl.compareAndSet(expect, expect + 1);
}

Worker

在之前的execute方法中,可以看到,添加线程并且执行任务是addWorker方法,在这里看一下addWorker方法和Worker类

addWorker方法:创建线程并且执行任务

private boolean addWorker(Runnable firstTask, boolean core) {
    // 1. 这个循环是判断线程数,如果符合要求,线程数加1
    retry:
    for (;;) {  // 自旋
        int c = ctl.get();
        // 判断线程池的运行状态
        int rs = runStateOf(c);
        // 没有必要创建新的worker的情况:线程池已关闭,或者线程池正在关闭 && 提交的任务是null && 阻塞队列中没有元素,
        // 直接返回
        if (rs >= SHUTDOWN &&
            ! (rs == SHUTDOWN &&
               firstTask == null &&
               ! workQueue.isEmpty()))
            return false;
        for (;;) {  // 自旋
            // 计算工作线程的个数
            int wc = workerCountOf(c);
            // 如果大于最大线程数,return false
            if (wc >= CAPACITY ||
                wc >= (core ? corePoolSize : maximumPoolSize))
                return false;
            // 线程数加1
            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 {
        // 创建worker实例,worker实例中封装了线程对象
        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();
                    // 将worker对象添加到集合中
                    workers.add(w);
                    int s = workers.size();
                    if (s > largestPoolSize)
                        largestPoolSize = s;
                    workerAdded = true;
                }
            } finally {
                mainLock.unlock();
            }
            if (workerAdded) {
                // 开启worker对象中封装的线程
                t.start();
                workerStarted = true;
            }
        }
    } finally {
        // 如果创建线程失败
        if (! workerStarted)
            addWorkerFailed(w);
    }
    return workerStarted;
}

总结:addWorker方法做的事情

  • 第一步:判断线程池状态,增加线程个数
  • 第二步:创建Worker实例,获取它持有的线程对象
  • 第三步:将Worker实例存放到HashSet容器中
  • 第四步:调用线程的start()方法,开启线程,新线程会执行Worker实例中的run方法

Worker类:ThreadPoolExecutor的成员内部类,继承了AbstractQueuedSynchronizer,这是juc中核心内容,实现了Runnable接口,

private final class Worker
    extends AbstractQueuedSynchronizer
    implements Runnable {

    // 持有的线程实例
    final Thread thread;
    // 线程执行的第一个异步任务
    Runnable firstTask;
    // 线程执行了多少任务
    volatile long completedTasks;

    // 构造方法
    Worker(Runnable firstTask) {
        setState(-1); // 调用了AbstractQueuedSynchronizer中的方法
        this.firstTask = firstTask;
        this.thread = getThreadFactory().newThread(this); // 调用线程工厂创建线程
    }

    // 线程启动后,会执行runWorker方法,同时传入当前实例
    public void run() {
        runWorker(this);
    }

    // 省略代码
}

// runWorker方法:获取传入worker实例中的task,如果task为null,则阻塞地获取队列中的task,执行task的run方法
final void runWorker(Worker w) {
    Thread wt = Thread.currentThread();
    Runnable task = w.firstTask;
    w.firstTask = null;
    w.unlock(); // allow interrupts
    boolean completedAbruptly = true;
    try {
        // 在getTask方法中,从阻塞队列中获取任务,如果获取不到异步任务,退出循环,执行finally中的方法,移除线程,
        // 在getTask方法中完成线程数减1的操作
        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 {
                    // 执行任务的run方法
                    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);  // 线程退出,将线程实例从线程池中移出
    }
}

Worker负责执行任务,它持有线程对象,会从阻塞队列中阻塞地获取异步任务,然后执行任务的run方法。

Worker类继承了AQS,实现了自己的锁机制,它的锁是不可重入锁,作用是,当Worker正在执行任务时,会获取锁,执行完后,会释放锁,当用户执行了shutdown方法,打断每个线程时,会尝试获取每个Worker实例的锁,如果可以获取到,证明当前线程没有执行任务,然后打断线程。

打断空闲线程的代码:

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()) {  // 尝试获取Worker实例的锁
                try {
                    t.interrupt();  // 如果获取到,打断空闲线程
                } catch (SecurityException ignore) {
                } finally {
                    w.unlock();
                }
            }
            if (onlyOne)
                break;
        }
    } finally {
        mainLock.unlock();
    }
}

当执行shutdownNow方法时,则是只要线程启动,就打断

void interruptIfStarted() {
    Thread t;
    // getState() >= 0,表示无论有没有获取锁,都打断。
    if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
        try {
            t.interrupt();
        } catch (SecurityException ignore) {
        }
    }
}

线程工厂

负责创建线程,核心接口是ThreadFactory,创建线程的主要工作就是指定线程名称、优先级、线程组

// ThreadFactory:线程工厂的接口
public interface ThreadFactory {
    // 创建线程的方法
    Thread newThread(Runnable r);
}

// ThreadFactory的默认实现,这是Executors的静态内部类
static class DefaultThreadFactory implements ThreadFactory {
    private static final AtomicInteger poolNumber = new AtomicInteger(1);
    // 线程组,默认使用当前线程的线程组
    private final ThreadGroup group;
    // 为线程编码,记录这是线程工厂创建的第几个线程
    private final AtomicInteger threadNumber = new AtomicInteger(1);
    // 线程名的前缀
    private final String namePrefix;

    DefaultThreadFactory() {
        SecurityManager s = System.getSecurityManager();
        group = (s != null) ? s.getThreadGroup() :
                              Thread.currentThread().getThreadGroup();
        namePrefix = "pool-" +
                      poolNumber.getAndIncrement() +
                     "-thread-";
    }

    // 创建线程:主要是为新线程命名,同时继承父线程的线程组和优先级
    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;
    }
}

阻塞队列

阻塞队列用于存放来不及执行的任务。

队列中定义的功能:

// Queue 队列的核心接口
public interface Queue<E> extends Collection<E> {
    // 添加元素
    boolean offer(E e);
    // 移除元素
    E poll();
    // 查看队列的第一个元素
    E peek();
}

// BlockQueue 阻塞队列,继承了Queue
public interface BlockingQueue<E> extends Queue<E> {
   // 语义上,是阻塞地获取元素
   E take() throws InterruptedException; 
}

从队列中获取元素:之前runWorker中的getTask方法

private Runnable getTask() {
    boolean timedOut = false; // Did the last poll() time out?

    for (;;) {
        // 判断线程池状态
        int c = ctl.get();
        int rs = runStateOf(c);

        // 判断状态:如果线程池状态是关闭,并且阻塞队列为空,
        if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
            decrementWorkerCount();  // 线程数减1
            return null;
        }

        // 获取线程数
        int wc = workerCountOf(c);

        // 获取异步任务时是否要指定超时时间,如果当前线程数大于核心线程数,则需要计时
        boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

        // 如果线程数超过最大线程数并且阻塞队列为空
        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;  // 超时
        } catch (InterruptedException retry) {
            timedOut = false;
        }
    }
}

拒绝策略

拒绝策略在代码设计上使用了策略模式,用户通过在创建线程池时传入不同类型的拒绝策略,可以控制线程池在无法执行异步任务时的行为。

// 核心接口:RejectedExecutionHandler
public interface RejectedExecutionHandler {
    // 拒绝异步任务的执行
    void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
}

// 默认实现:AbortPolicy 抛异常
public static class AbortPolicy implements RejectedExecutionHandler {
    public AbortPolicy() { }

    // 抛异常
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        throw new RejectedExecutionException("Task " + r.toString() +
                                             " rejected from " +
                                             e.toString());
    }
}

关闭线程池

shutdown方法:

public void shutdown() {
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        // java自带的安全检查工具,使用SecurityManage
        checkShutdownAccess();
        // 更改线程池的状态为SHUTDOWN
        advanceRunState(SHUTDOWN);
        // 所有的线程实例都调用interrupt方法
        interruptIdleWorkers();
        // 扩展点
        onShutdown(); // hook for ScheduledThreadPoolExecutor
    } finally {
        mainLock.unlock();
    }
    // 尝试终止线程池
    tryTerminate();
}

shutdownNow方法:

public List<Runnable> shutdownNow() {
    List<Runnable> tasks;
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        // java自带的安全检查工具
        checkShutdownAccess();
        // 更改线程池的状态为STOP
        advanceRunState(STOP);
        // 所有的线程实例都调用interrupt方法
        interruptWorkers();
        // 将阻塞队列中的异步任务都抽取出来,返回给调用方
        tasks = drainQueue();
    } finally {
        mainLock.unlock();
    }
    tryTerminate();
    return tasks;
}

总结:shutdown和shutdownNow方法,都会调用interrupt方法,打断正在执行任务的线程,线程内部会把任务执行完再退出。不同点在于,shutdow方法会执行完阻塞队列中的任务,shutdownNow方法会把阻塞队列中的任务提取出来,返回给调用端,所以它是立刻关闭。

你可能感兴趣的:(java)