「源码学习」ThreadPoolExecutor类

53 阅读3分钟

学习了Thread源码后,接下来学习一下线程池,在看源码前,先看一下该组件的几个接口、抽象类和实现类的结构关系。

Executor接口

ThreadPoolExecutor实现的顶层接口,顶层接口提供了一种思想:将任务提交和任务执行进行解耦。用户无需关注如何创建线程和如何调度线程执行任务,用户只需要提供Runnable对象,将任务执行逻辑提交到执行器中,由Executor框架完成线程的调配和任务的执行部分。

public interface Executor {
    void execute(Runnable command);
}

ExecutorService接口

扩充一个或一批异步任务生成Future的submit()方法。提供了shutdown()关闭线程池方法。

public interface ExecutorService extends Executor {

    void shutdown();

    <T> Future<T> submit(Callable<T> task);

    <T> Future<T> submit(Runnable task, T result);

    Future<?> submit(Runnable task);
}

AbstractExecutorService接口

将任务执行流程串起来,实现层只需要关注一个执行任务的方法。使用了“模板方法模式”,其它线程池想实现这些方法只需要实现Executor.execute()方法就可以了。

/**
 * 该类主要实现了 ExecutorService 中的 submit()方法
 */
public abstract class AbstractExecutorService implements ExecutorService {

    /**
     * 提交任务,执行任务,返回获取未来结果的 Future对象。
     * 模板方法模式
     */
    public Future<?> submit(Runnable task) {
        if (task == null) throw new NullPointerException();
        R unnableFuture<Void> ftask = newTaskFor(task, null);
        execute(ftask);
        return ftask;
    }

    public <T> Future<T> submit(Runnable task, T result) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task, result);
        execute(ftask);
        return ftask;
    }

    public <T> Future<T> submit(Callable<T> task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task);
        execute(ftask);
        return ftask;
    }
}

ThreadPoolExecutor

学习ThreadPoolExecutor源码前,贴一个ThreadPoolExecutor的使用示例代码。

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ThreadPoolExecutorDemo {

    private static final int CORE_POOL_SIZE = 5;
    private static final int MAX_POOL_SIZE = 10;
    private static final int QUEUE_CAPACITY = 100;
    private static final Long KEEP_ALIVE_TIME = 1L;

    public static void main(String[] args) {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                CORE_POOL_SIZE,
                MAX_POOL_SIZE,
                KEEP_ALIVE_TIME,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(QUEUE_CAPACITY),
                new ThreadPoolExecutor.CallerRunsPolicy());

        for (int i = 0; i < 10; i++) {
            Runnable worker = new MyRunnable("thread-" + i);
            executor.execute(worker);
        }
        //关闭线程池
        executor.shutdown();
    }
}

class MyRunnable implements Runnable {

    private String name;

    public MyRunnable(String name){
        this.name = name;
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + ">>" + name);
    }
}

日志输出

pool-1-thread-1>>thread-0
pool-1-thread-4>>thread-3
pool-1-thread-3>>thread-2
pool-1-thread-2>>thread-1
pool-1-thread-4>>thread-7
pool-1-thread-2>>thread-8
pool-1-thread-3>>thread-6
pool-1-thread-1>>thread-5
pool-1-thread-4>>thread-9
pool-1-thread-5>>thread-4

进入主题>>>>

下面主要看一下ThreadPoolExecutor的主要代码部分。

主要属性

说起线程池,随口而出的便是它的主要属性:核心线程数、最大线程数、空闲时间、阻塞队列、拒绝策略。

   //阻塞队列
    private final BlockingQueue<Runnable> workQueue;

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

    //核心线程数
    private volatile int corePoolSize;

    //最大线程数
    private volatile int maximumPoolSize;

    //线程池维护线程所允许的空闲时间
    private volatile long keepAliveTime;
    
    //拒绝策略
    private volatile RejectedExecutionHandler handler;

构造方法

//最后都使用了最后一个构造方法的实现
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
                Executors.defaultThreadFactory(), defaultHandler);
    }

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
                threadFactory, defaultHandler);
    }

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              RejectedExecutionHandler handler) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
                Executors.defaultThreadFactory(), handler);
    }

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

拒绝策略

   /**
     * 线程池对拒绝任务的处理策略,4种策略
     */
    private volatile RejectedExecutionHandler handler;

    //默认拒绝策略
    private static final RejectedExecutionHandler defaultHandler =
            new java.util.concurrent.ThreadPoolExecutor.AbortPolicy();

   //1.AbortPolicy:默认策略,丢弃任务并抛出RejectedExecutionException异常。
    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());
        }
    }
   //2.CallerRunsPolicy:由调用线程(提交任务的线程)处理该任务。
    public static class CallerRunsPolicy implements RejectedExecutionHandler {
        public CallerRunsPolicy() { }
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                r.run();
            }
        }
    }
    //3.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新提交被拒绝的任务。
    public static class DiscardOldestPolicy implements RejectedExecutionHandler {
        public DiscardOldestPolicy() { }
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                e.getQueue().poll();
                e.execute(r);
            }
        }
    }
   //4.DiscardPolicy:丢弃任务,但不抛出异常。
    public static class DiscardPolicy implements RejectedExecutionHandler {
        public DiscardPolicy() { }
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        }
    }

主要实现

   /**
     * 执行线程任务
     * @param command
     */
    public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        /*
         * 分三步进行:
         * 1、如果运行的线程小于核心线程数,尝试开启一个新的线程;否则尝试进入工作队列。
         * 2、如果工作队列没满,则进入工作队列;否则判断是否超出最大线程数
         * 3、如果未超出最大线程数,则尝试开启一个新的线程;否则按饱和策略处理无法执行的任务
         */
        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);
    }

    /**
     * 在此过程中执行以前提交的任务,但不会接受新任务。如果调用已关闭,则不会产生额外的影响。
     */
    public void shutdown() {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            checkShutdownAccess();
            advanceRunState(SHUTDOWN);
            interruptIdleWorkers();
            onShutdown(); // hook for ScheduledThreadPoolExecutor
        } finally {
            mainLock.unlock();
        }
        tryTerminate();
    }

ThreadPoolExecutor 中的 execute()方法执行Runnable任务的流程逻辑可以用下图表示。

Executors工具类

在上面写了一个ThreadPoolExecutor使用的demo,下面简单介绍一下Executors线程池工具类。

它主要的作用就是提供一些static 的工具方法,为开发者提供各种封装好的具有各自特性的线程池,方便开发者创建线程池。

public class Executors {

    /**
     * 创建一个核心线程数和最大线程数相等的线程池
     */
    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

    /**
     * 创建一个单线程的线程池
     */
    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

    /**
     * 创建可动态伸缩的线程池。
     * 核心线程数为0,最大线程数为Integer.MAX_VALUE,如果任务数在某一瞬间暴涨,存在一定的风险。
     */
    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }
}

贴一个Executors的示例代码。

public class ExecutorsDemo {

    public static void main(String[] args) {
        ExecutorService threadPool = Executors.newFixedThreadPool(3);

        for (int i = 0; i < 10; i++) {
            Runnable worker = new MyRunnable("thread-" + i);
            threadPool.execute(worker);
        }
        //关闭线程池
        threadPool.shutdown();
    }
}

日志输出

pool-1-thread-1>>thread-0
pool-1-thread-2>>thread-1
pool-1-thread-3>>thread-2
pool-1-thread-1>>thread-3
pool-1-thread-3>>thread-4
pool-1-thread-1>>thread-6
pool-1-thread-2>>thread-5
pool-1-thread-1>>thread-8
pool-1-thread-3>>thread-7
pool-1-thread-2>>thread-9

在日常的微服务开发的时候,大多都已习惯在spring环境下开发,经常用到的线程池便是ThreadPoolTaskExecutor,它和ThreadPoolExecutor有啥区别呢?

1、ThreadPoolTaskExecutor中使用了ThreadPoolExecutor,并对其进行了增强,扩展了更多的自有特性。 2、ThreadPoolTaskExecutor只关注自己扩展的那一部分特性,任务的执行还是由ThreadPoolExecutor来处理。 3、ThreadPoolTaskExecutor针对spring用起来更友好,离开spring我们用ThreadPoolExecutor。