第九章 ThreadPoolExecutor源码解析

ThreadPoolExecutor使用 + 工作机理 + 生命周期

1、最基础的线程池ThreadPoolExecutor

使用方式:

1 /**
 2  * ThreadPoolExecutor测试类
 3  * 注意:
 4  * 1、ThreadPoolExecutor是一个线程池
 5  * 2、多个任务都可以由该线程池中选出几条线程来执行
 6  */
 7 public class ThreadPoolExecutorTest {
 8     private static ThreadPoolExecutor executor = 
 9             new ThreadPoolExecutor(5, 10, 30, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(10));
10     
11     public void executeTask(){
12         Task1 task1 = new Task1();//构建任务1
13         Task2 task2 = new Task2();//构建任务2
14         executor.execute(task1);//执行任务1
15         executor.execute(task2);//执行任务2
16     }
17     
18     /*
19      * 基本任务2
20      */
21     class Task1 implements Runnable{
22         public void run() {
23             //具体任务的业务
24             for(int i=0;i<1000;i++){
25                 System.out.println("hello xxx!!!");
26             }
27         }
28     }
29     
30     /*
31      * 基本任务2
32      */
33     class Task2 implements Runnable{
34         public void run() {
35             //具体任务的业务
36             for(int i=0;i<5;i++){
37                 System.out.println("hello world2!!!");
38             }
39         }
40     }
41     
42     public static void main(String[] args) {
43         ThreadPoolExecutorTest test = new ThreadPoolExecutorTest();
44         test.executeTask();
45     }
46 }

说明:

在代码中,构建了一个线程池(executor)和两个实现了Runnable接口的任务(task1、task2),并将这两个任务提交到executor中去执行。

线程池的配置:集合下边的工作机理与参数详细说明来说。

当然,上述的执行结果是交叉着的,因为存在线程的切换。

 

2、工作机理

A、当一个新的任务被提交到ThreadPoolExecutor的execute()方法中时,如果当前池中正在运行的线程少于corePoolSize,则会创建一个新的线程来处理该任务;

注意:这是池中正在运行的线程,为什么这样说呢?是因为核心线程是每来一个任务才创建一个线程,这个看第三部分。看完第三部分之后,你就会觉得,其实换个说法:"如果当前池中的线程少于corePoolSize"这样会更准确,因为我们也许会通过下边介绍的方法提前将核心线程创建好,如果假设这时候来了一个任务,而所有的核心线程都处于空闲状态的话,这时候是不会去创建新线程的。

B、如果当前池中的线程大于等于corePoolSize,但是小于maximumPoolSize时,如果队列满了,会创建新的线程来处理任务,如果队列没有满,任务加入到队列中去;

C、如果队列满了,正在运行的线程数已经等于maximumPoolSize时,该任务就会被rejected(回绝)

 

3、参数详细说明

A、corePoolSize与maximumPoolSize

  • 如果corePoolSize==maximumPoolSize,线程池的size就是固定的了(这一块儿类似于堆内存的指定,防止扩张带来的损耗,但要视情况而定);
  • 默认情况下,只有当一个新的任务到达时,才会创建和启动core threads,但是可以通过prestartCoreThread和prestartAllCoreThreads来改变;

B、ThreadFactory

  • 通过使用java.util.concurrent.ThreadFactory可以创建新的线程
  • 如果不额外指定ThreadFactory,则使用默认的Executors#defaultThreadFactory
  • 通过该默认的线程工厂,所有创建的线程都会被加入到同一个ThreadGroup中去,并且这些线程都会有相同的优先级(NORM_PRIORITY),并且都是non-daemon线程

注意:这一块儿有一个后台(daemon)线程的概念,典型的后台线程:垃圾回收线程;这个线程与其他应用线程的不同之处在于:当所有的应用线程都没有后,后台线程也就自动消失了。

C、keepAliveTime

  • 如果pool当前拥有的线程超过了corePoolSize,超出的线程如果在大于keepAliveTime的时间外闲置(idle),这些线程就会被终止;
  • 该机制在pool没有被活跃的使用的时候,可以减少资源浪费;
  • 默认情况下,keep-alive机制仅仅会在线程数超过corePoolSizeThreads时才会被使用;
  • 当然,通过使用ThreadPoolExecutor#allowCoreThreadTimeOut(boolean)也可以将这种keep-alive机制应用在core threads上去(只要keepAliveTime>0即可)

D、Queue

任何一种BlockingQueue都可以被用来传递和存储提交到线程池中的任务,有三种队列策略:

1)SynchronousQueue(默认)

  • 直接将任务移交给线程而不是入队,如果已经没有线程立即来处理提交到pool中的任务时,会创建一个新的线程来处理该任务;
  • 这种策略需要maximumPoolSizes无界来确保新提交的任务不会被rejection;
  • 这种方式的最大缺点:当任务到来的速度大于任务被处理的速度时,线程数会疯长。

2)无界队列LinkedBlockingQueue:

  • 由于队列无界,当运行的线程等于corePoolSize时,新到来的任务会入队而不会创建新的线程来执行(即pool中的线程数永远不会大于corePoolSize);
  • 这种方式的缺点:当任务到来的速度大于任务被处理的速度时,队列长度会疯长。

3)有界队列ArrayBlockingQueue:

  • 这种方式是非常难处理好的一种方式,要考虑好ArrayBlockingQueue的大小和maximumPoolSize的大小;
  • 当ArrayBlockingQueue较大而maximumPoolSize较小时,会降低CPU使用率、减少OS资源、减少上下文切换,但是吞吐量会降低。-->线程较少的特点就是这样;
  • 如果任务频繁的被阻塞(例如,they are I/O bound),就需要更多的线程了;
  • 当ArrayBlockingQueue较小而maximumPoolSize较大时,会使CPU使用繁忙但也会遇到一些不可接受的scheduling,吞吐量也会降低。

说明:这一块儿配置是一个比较麻烦的地方,后边会说。

E、回绝任务

执行回绝的场景:看开头部分的工作机理。

在回绝任务的时候,execute()方法会调用RejectedExecutionHandler#rejectedExecution。有四种handler策略:

1)ThreadPoolExecutor.CallerRunsPolicy:调用execute()的线程自己来处理该任务,绝大部分情况下是主线程。

注意:由于主线程执行这个任务,那么新到来的任务就不会被提交到线程池中执行(而是提交到TCP层的队列,TCP层队列满了,就开始拒绝,此时性能已经很低了),直到主线程执行完这个任务。

2)ThreadPoolExecutor.DiscardPolicy:不能被执行的任务会直接被扔掉

3)ThreadPoolExecutor.DiscardOldestPolicy:如果executor没有被关闭,队列头部的任务将会被丢弃,然后将该任务加到队尾

4)ThreadPoolExecutor.AbortPolicy(默认):回绝任务并抛出异常

F、AOP

ThreadPoolExecutor提供了两个方法在每个任务的执行前后进行调用ThreadPoolExecutor#beforeExecute和ThreadPoolExecutor#afterExecute.

 

4、开头实例套用

实例中构建的线程池参数:

  • corePoolSize==5    
  • maximumPoolSize==10  
  • keepAliveTime==30s 
  • 队列:ArrayBlockingQueue,大小为10
  • 线程工厂:defaultThreadFactory(默认)
  • 回绝策略:AbortPolicy(默认)

套一下工作机理:

1)当并发提交了<=5个任务到executor中时(此时任务数<=corePoolSize),executor会使用5个核心线程去执行这些任务;

2)当这时候马上又来了一个任务,如果此时5个核心线程有空闲线程的话,就是用空闲的线程去处理,如果都在忙,这时候该任务进入队列;

3)之后再来任务,还是像第二步那样去执行,直到任务将队列放满了,这时候,如果再来一个任务,如果5个核心线程有空闲线程,直接去执行该任务,如果5个核心线程都在忙,这时候就创建一个新的线程来执行该任务;

4)如果通过上边的流程,最后5个线程都在忙,并且队列满了,并且pool中的线程数已经是10个了(池中的线程总数==maximumPoolSize了),这时候就要执行回绝策略了,在这里,使用了默认的AbortPolicy,即直接放弃该任务并抛出异常。

在代码的执行过程中,如果发现后来创建的5个线程有超过30秒都没被调用过的,该线程就被回收掉了。

5、线程池生命周期 

  • 创建之初,状态为RUNNNG
  • 调用了ExecutorService#shutdown:将之前已经提交上来的任务进行处理(包括队列中的),但是不再接收新任务(使用回绝策略回绝新任务),状态SHUNTDOWN
  • 调用了ExecutorService#shutdownNow:取消所有运行中的任务(包括队列中的),并且不再接收新任务(使用回绝策略回绝新任务),状态STOP/TERMINATED

疑问:(这个疑问我会在看完ThreadPoolExecutor的相关源码后进行回答)

当队列满了之后,这时候来了一个任务,恰好5个核心线程有一个空闲了,那么下面两种情况哪一个正确:

1)这个空闲的核心线程直接执行刚刚到来的任务

2)这个空闲的核心线程直接执行队列头部的任务,而将刚刚到来的任务放入队尾

解答:这个问题的答案就一句话,有空闲核心线程,就是用核心线程去执行任务;没有空闲的核心线程,任务才会入队。所以选1)

ThreadPoolExecutor源码解析

1、源代码主要掌握两个部分

  • 线程池的创建:构造器
  • 提交任务到线程池去执行:execute()

2、构造器

2.1、一些属性:

/**
     * runState provides the main lifecyle control, taking on values:
     *
     * RUNNING -> SHUTDOWN
     *    On invocation of shutdown(), perhaps implicitly in finalize()
     * (RUNNING or SHUTDOWN) -> STOP
     *    On invocation of shutdownNow()
     * SHUTDOWN -> TERMINATED
     *    When both queue and pool are empty
     * STOP -> TERMINATED
     *    When pool is empty
     */
    volatile int runState;
    static final int RUNNING    = 0;//接收新的任务,会处理队列中的任务
    static final int SHUTDOWN   = 1;//不接收新的任务,但是会处理队列中的任务
    static final int STOP       = 2;//不接收新的任务,也不会处理队列中的任务,而且还会中断正在执行的任务
    static final int TERMINATED = 3;//STOP+中止所有线程

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

    /**
     * 对poolSize, corePoolSize, maximumPoolSize, runState, and workers set上锁
     */
    private final ReentrantLock mainLock = new ReentrantLock();

    /**
     * 支持awaitTermination的等待条件
     */
    private final Condition termination = mainLock.newCondition();

    /**
     * pool中的所有工作线程集合;仅仅在持有mainLock的时候才允许被访问
     */
    private final HashSet<Worker> workers = new HashSet<Worker>();

    private volatile long  keepAliveTime;

    /**
     * false(默认):当核心线程处于闲置状态时,也会存活
     * true:核心线程使用keepAliveTime来决定自己的存活状态
     */
    private volatile boolean allowCoreThreadTimeOut;

    /**
     * Core pool size,仅仅在持有mainLock的时候才允许被更新, 
     * 因为是volatile允许并发读(即使是在更新的过程中)
     */
    private volatile int   corePoolSize;

    /**
     * Maximum pool size, 其他同上
     */
    private volatile int   maximumPoolSize;

    /**
     * Current pool size, 其他同上
     */
    private volatile int   poolSize;

    /**
     * 回绝处理器
     */
    private volatile RejectedExecutionHandler handler;

    /**
     * 所有的线程都通过这个线程工厂的addThread方法来创建。
     */
    private volatile ThreadFactory threadFactory;

    /**
     * Tracks largest attained pool size.
     */
    private int largestPoolSize;

    /**
     * 已经完成的任务数.仅仅在工作线程被终结的时候这个数字才会被更新 
     */
    private long completedTaskCount;

    /**
     * 默认的回绝处理器(回绝任务并抛出异常)
     */
    private static final RejectedExecutionHandler defaultHandler =
        new AbortPolicy();

说明:因为属性不多,这里列出了全部属性。

 

2.2、构造器:

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个构造器(1个5参+2个6参+1个7参)

注意:默认情况下,构造器只会初始化参数,不会提前构建好线程

建议:构造器参数众多,建议使用构建器模式,关于构建器模式的实际使用范例,请参照《第二章 Google guava cache源码解析1--构建缓存器

构造器中默认线程工厂的创建:Executors中的方法

public static ThreadFactory defaultThreadFactory() {
        return new DefaultThreadFactory();
    }

    /**
     * 默认的线程工厂
     */
    static class DefaultThreadFactory implements ThreadFactory {
        static final AtomicInteger poolNumber = new AtomicInteger(1);//池数量
        final ThreadGroup group;//线程组
        final AtomicInteger threadNumber = new AtomicInteger(1);//线程数量
        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);
            /*
             * 将线程的优先级全部设置为NORM_PRIORITY
             */
            if (t.getPriority() != Thread.NORM_PRIORITY)
                t.setPriority(Thread.NORM_PRIORITY);
            return t;
        }
    }

说明,其中的newThread()方法会在第三部分用到。

 

3、提交任务的线程池去执行execute(Runnable command)

public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        /**
         * 这一块儿就是整个工作机理的部分(代码比较精致)
         * 1、addIfUnderCorePoolSize
         * 1)如果当前线程数poolSize<核心线程数corePoolSize并且pool的状态为RUNNING,
         * 1.1)先获取锁
         * 1.2)根据传入的任务firstTask创建一个Work对象,在该对象中编写了run()方法,在该run()方法中会真正的去执行firstTask的run()
         * 说明:关于Work对象run部分的内容,查看Work内部类的run()方法上边的注释以及与其相关方法的注释
         * 1.3)通过线程工厂与上边创建出来的work对象w创建新的线程t,将w加入工作线程集合,
         * 然后启动线程t,之后就会自动执行w中的run(),w中的run()又会调用firstTask的run(),即处理真正的业务逻辑
         * 
         * 2、如果poolSize>=corePoolSize或者上边的执行失败了
         * 1)如果pool的状态处于RUNNING,将该任务入队(offer(command))
         * 如果入队后,pool的状态不是RUNNING了或者池中的线程数为0了,下边的逻辑具体去查看注释
         * 2)addIfUnderMaximumPoolSize(同addIfUnderCorePoolSize)
         * 如果增加线程也不成功,则回绝任务。
         * 
         */
        if (poolSize >= corePoolSize || !addIfUnderCorePoolSize(command)) {
            if (runState == RUNNING && workQueue.offer(command)) {
                if (runState != RUNNING || poolSize == 0)
                    ensureQueuedTaskHandled(command);
            }
            else if (!addIfUnderMaximumPoolSize(command))
                reject(command); // is shutdown or saturated
        }
    }

 

3.1、addIfUnderCorePoolSize(Runnable firstTask)

/**
     * 创建并且启动一个新的线程来处理任务
     * 1、其第一个任务就是传入的firstTask参数
     * 2、该方法仅仅用于当前线程数小于核心线程数并且pool没有被关掉的时候
     */
    private boolean addIfUnderCorePoolSize(Runnable firstTask) {
        Thread t = null;
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();//获取锁
        try {
            if (poolSize < corePoolSize && runState == RUNNING)
                t = addThread(firstTask);//创建新线程
        } finally {
            mainLock.unlock();//释放锁
        }
        return t != null;
    }

addThread(Runnable firstTask)

private Thread addThread(Runnable firstTask) {
        Worker w = new Worker(firstTask);//构造一个work
        Thread t = threadFactory.newThread(w);//创建线程
        boolean workerStarted = false;
        if (t != null) {//
            if (t.isAlive()) //如果t线程已经启动了,而且还没有死亡
                throw new IllegalThreadStateException();
            w.thread = t;
            workers.add(w);//将w工作线程加入workers线程池
            int nt = ++poolSize;//当前的池数量+1
            if (nt > largestPoolSize)
                largestPoolSize = nt;
            try {
                t.start();//启动线程
                workerStarted = true;
            }
            finally {
                if (!workerStarted)//启动线程没有成功
                    workers.remove(w);//将w从workers集合中删除
            }
        }
        return t;
    }

newThread(Runnable r)

该方法在构建上边的默认线程工厂部分已经说过了。

 

Work内部类:

/**
     * 工作线程。
     */
    private final class Worker implements Runnable {
        /**
         * 在每一个任务的执行前后都会获取和释放runLock。
         * 该锁只要是为了防止中断正在执行任务的work线程
         */
        private final ReentrantLock runLock = new ReentrantLock();

        /**
         * Initial task to run before entering run loop. 
         * 1、Possibly null.
         */
        private Runnable firstTask;

        /**
         * 每个work线程完成的任务总量
         * accumulated into completedTaskCount upon termination.
         */
        volatile long completedTasks;

        Thread thread;

        /**
         * 该work中的线程是不是确实正在执行了run()
         */
        volatile boolean hasRun = false;

        Worker(Runnable firstTask) {
            this.firstTask = firstTask;
        }

        /*
         * true:已经有线程持有了该锁
         */
        boolean isActive() {
            return runLock.isLocked();
        }

        private void runTask(Runnable task) {
            final ReentrantLock runLock = this.runLock;
            runLock.lock();//获取锁runLock
            try {
                /*
                 * 如果pool状态为STOP或TERMINATED,确保线程被打断;
                 * 如果不是,确保线程不要被打断
                 */
                if ((runState >= STOP ||
                    (Thread.interrupted() && runState >= STOP)) &&
                    hasRun)
                    thread.interrupt();
                /*
                 * 确保afterExecute会被执行仅仅当任务完成了(try)或抛出了异常(catch)
                 */
                boolean ran = false;
                beforeExecute(thread, task);//执行任务的run()方法之前要执行的操作
                try {
                    task.run();//执行线程的run()方法
                    ran = true;
                    afterExecute(task, null);//执行任务的run()方法之后要执行的操作
                    ++completedTasks;
                } catch (RuntimeException ex) {
                    if (!ran)
                        afterExecute(task, ex);
                    throw ex;
                }
            } finally {
                runLock.unlock();//释放锁runLock
            }
        }

        /**
         * Main run loop
         * 运行当前任务task,运行结束后,尝试获取队列中的其他任务,
         * 如果最后通过各种方式都获取不到,就回收该线程,如果获取到了,就用该线程继续执行接下来的任务
         * 最后,当获取不到任何任务去执行时,就将该线程从works线程集合中删除掉
         */
        public void run() {
            try {
                hasRun = true;
                Runnable task = firstTask;
                firstTask = null;
                while (task != null || (task = getTask()) != null) {
                    runTask(task);//运行该任务
                    task = null;
                }
            } finally {
                workerDone(this);//将该线程从works集合中删除
            }
        }
    }

说明:这里列出了该内部类的全部属性和常用方法。

 

getTask()

/**
     * 获取下一个worker线程将要运行的任务
     * Gets the next task for a worker thread to run.  
     */
    Runnable getTask() {
        for (;;) {//无限循环
            try {
                int state = runState;
                if (state > SHUTDOWN)
                    return null;
                Runnable r;
                if (state == SHUTDOWN)  // Help drain queue
                    r = workQueue.poll();//处理queue中的任务
                //下面的runState==RUNNING
                else if (poolSize > corePoolSize || allowCoreThreadTimeOut)
                    //从队头获取任务,如果没有任务,等待keepAliveTime的时间
                    r = workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS);
                else
                    //从队头获取任务,如果没有任务,阻塞等待
                    r = workQueue.take();
                if (r != null)
                    return r;
                if (workerCanExit()) {//允许回收获取任务失败的线程
                    if (runState >= SHUTDOWN) // Wake up others
                        interruptIdleWorkers();//中断闲置的work线程
                    return null;
                }
                // Else retry
            } catch (InterruptedException ie) {
                // On interruption, re-check runState
            }
        }
    }

workerCanExit()

/**
     * 检测一个获取任务失败的work线程是否可以退出了。
     * 出现下面三种情况,work线程就会死亡。
     * 1、如果pool的状态为STOP或TERMINATED
     * 2、队列为空
     * 3、允许回收核心线程并且池中的线程数大于1和corePoolSize的最大值
     */
    private boolean workerCanExit() {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        boolean canExit;
        try {
            canExit = runState >= STOP ||
                workQueue.isEmpty() ||
                (allowCoreThreadTimeOut &&
                 poolSize > Math.max(1, corePoolSize));
        } finally {
            mainLock.unlock();
        }
        return canExit;
    }

workerDone(Worker w)

void workerDone(Worker w) {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            completedTaskCount += w.completedTasks;
            workers.remove(w);//从workers集合中删除该线程
            if (--poolSize == 0)//如果池中的线程数为0
                tryTerminate();
        } finally {
            mainLock.unlock();
        }
    }

3.2、ensureQueuedTaskHandled(Runnable command)

/**
     * 在一个task入队之后重新检查state。
     * 当一个task入队后,pool的state发生了变化,该方法就会被调用。
     * 如果一个task入队的同时,shutdownNow方法发生了调用,该方法就必须从队列中移除并回绝
     * 否则该方法会保证至少有一个线程来处理入队的task
     */
    private void ensureQueuedTaskHandled(Runnable command) {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        boolean reject = false;
        Thread t = null;
        try {
            int state = runState;
            if (state != RUNNING && workQueue.remove(command))
                reject = true;
            else if (state < STOP &&
                     poolSize < Math.max(corePoolSize, 1) &&
                     !workQueue.isEmpty())
                t = addThread(null);
        } finally {
            mainLock.unlock();
        }
        if (reject)
            reject(command);
    }

 

3.3、addIfUnderMaximumPoolSize(Runnable firstTask)

private boolean addIfUnderMaximumPoolSize(Runnable firstTask) {
        Thread t = null;
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            if (poolSize < maximumPoolSize && runState == RUNNING)
                t = addThread(firstTask);
        } finally {
            mainLock.unlock();
        }
        return t != null;
    }

说明:该方法的其他方法与addIfUnderCorePoolSize(Runnable firstTask)一样。

 

3.4、reject(Runnable command)

void reject(Runnable command) {
        handler.rejectedExecution(command, this);
    }
 public static class AbortPolicy implements RejectedExecutionHandler {
        
        public AbortPolicy() { }
        /** 直接抛异常 */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            throw new RejectedExecutionException();
        }
    }

 

posted @ 2022-05-21 10:59  hanease  阅读(45)  评论(0编辑  收藏  举报