ThreadPoolExecutor详细教程

ThreadPoolExecutor

一、概况

ThreadPoolExecutor是创建线程池对象,通过ThreadPoolExecutor可以创建线程池,但为什么不适用Executors创建呢,不是更简单吗,在《阿里巴巴java开发手册》里就建议使用ThreadPoolExecutor创建线程,而不是Executors;

原因:Executors创建线程池使用的队列都是无界队列,在设备内存有限的情况下,如果使用无限队列,会导致队列所存的数据大与设备内存,从而导致OOM,而使用ThreadPoolExecutor创建可以自定义队列,使用有界队列;

二、类图关系

在这里插入图片描述

三、四大构造函数

在这里插入图片描述

​ 构造函数里都调用this.prestartAllCoreThreads();方法,这个方法是启动所有核心线程,返回启动的核心线程总数

该方法里调用addWorker()方法

addWorker()方法:他的主池控制状态ctl是一个原子整数包装两个概念字段 workerCount,指示有效线程数runState,指示是否运行,关闭等

也就是初始化线程池时会创建所有的核心线程,使用while循环调用addWorker方法,

  1. 线程初始化过程:
private boolean addWorker(Runnable firstTask, boolean core) {
        retry:
        // 判断线程池状态
        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);
 
            // Check if queue empty only if necessary.
            // 当线程池状态至少为SHUTDOWN,且以下三个条件任意一个为false时,则返回false,拒绝创建新的worker
            // 1、rs == SHUTDOWN的false情况:线程池状态已经超过shutdown,可能是stop、tidying、terminated其中一个,即线程池已经终止
            // 2、firstTask == null的false情况:firstTask不为空,场景是在线程池已经shutdown后,还要添加新的任务,拒绝
            // 3、!workQueue.isEmpty()的false情况:workQueue为空,且rs >= SHUTDOWN,那么就没有添加新worker线程的必要了
            if (rs >= SHUTDOWN &&
                ! (rs == SHUTDOWN &&
                   firstTask == null &&
                   ! workQueue.isEmpty()))
                return false;
 
            for (;;) {
                int wc = workerCountOf(c);
                // 这里判断线程数量是否超过边界,根据参数true or false来选择corePoolSize or maximumPoolSize,若超过边界,则拒绝任务
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;
                // 这里若成功将将线程数量+1,则跳出retry循环
                if (compareAndIncrementWorkerCount(c))
                    break retry;
                // 若没有成功将线程数量+1,则判断线程状态是否有改变,若改变了,则跳到外层循环重新执行之前的流程,若状态没有改变,则继续内层循环
                c = ctl.get();  // Re-read ctl
                if (runStateOf(c) != rs)
                    continue retry;
                // else CAS failed due to workerCount change; retry inner loop
            }
        }
        // worker数量+1成功的后续操作,添加到workers Set集合,并启动worker线程
        boolean workerStarted = false;
        boolean workerAdded = false;
        Worker w = null;
        try {
            // 1、设置worker这个AQS锁的同步状态state=-1
            // 2、将firstTask设置给worker的成员变量firstTask
            // 3、使用worker自身这个runnable,调用ThreadFactory创建一个线程,并设置给worker的成员变量thread
            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());
                    // 如果线程池在RUNNING状态,或者线程池已经在SHUTDOWN状态且firstTask==null(可能是workQueue中仍有未执行完成的任务,创建没有初始任务的worker线程执行)
                    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 {
            // 若启动线程失败,将worker从workers中移除,worker数量-1,并尝试中断线程
            if (! workerStarted)
                addWorkerFailed(w);
        }
        return workerStarted;
    }
  1. 线程回收机制:如果没设置allowCoreThreadTimeOut为false(默认),即使核心线程空闲也不会回收,只回收超出核心线程数的其他线程,而如果为true,则会和其他线程一样,当线程空闲后会按照keepAliveTime超时时间进行回收

在执行任务时,执行完毕后会在finally中调用processWorkerExit方法,该方法就是

 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 pool is stopping, ensure thread is interrupted;
                // if not, ensure thread is not interrupted.  This
                // requires a recheck in second case to deal with
                // shutdownNow race while clearing interrupt
                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);
        }
    }

processWorkerExit方法具体执行:

 private void processWorkerExit(Worker w, boolean completedAbruptly) {
        if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
            decrementWorkerCount();

        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            //completedTaskCount记录完成的任务数累加
            completedTaskCount += w.completedTasks;
            //从hashset中移除改线程
            workers.remove(w);
        } finally {
            mainLock.unlock();
        }

        tryTerminate();

        int c = ctl.get();
        if (runStateLessThan(c, STOP)) {
            if (!completedAbruptly) {
                int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
                if (min == 0 && ! workQueue.isEmpty())
                    min = 1;
                if (workerCountOf(c) >= min)
                    return; // replacement not needed
            }
            addWorker(null, false);
        }
    }

线程池状态:

在这里插入图片描述

其中ctl这个AtomicInteger原子操作类的功能很强大,其高3位用于维护线程池运行状态,低29位维护线程池中线程数量。

1、RUNNING:-1<<COUNT_BITS,即高3位为111,低29位为0,该状态的线程池会接收新任务,也会处理在阻塞队列中等待处理的任务;

2、SHUTDOWN:0<<COUNT_BITS,即高3位为000,低29位为0,该状态的线程池不会再接收新任务,但还是会处理已经提交到阻塞队列中等待处理的任务;

3、STOP:1<<COUNT_BITS,即高3位为001,低29位为0,该状态的线程池不会再接收新任务,不会处理在阻塞队列中等待的任务,而且还会中断正在运行的任务;

4、TIDYING:2<<COUNT_BITS,即高3位为010,低29位为0,所有任务都被终止了,线程数量workerCount为0,为此状态时还将调用terminated()方法,terminated()方法由子类实现;

5、TERMINATED:3<<COUNT_BITS,即高3位为011,低29位为0,terminated()方法调用完成后变成此状态。

这些状态均由int型表示,大小关系为 RUNNING<SHUTDOWN<STOP<TIDYING<TERMINATED,这个顺序基本上也是遵循线程池从运行到终止这个过程。

runStateOf(int c)方法:c & 高3位为1,低29位为0的~CAPACITY,用于获取高3位保存的线程池状态。

workerCountOf(int c)方法:c & 高3位为0,低29位为1的CAPACITY,用于获取低29位的线程数量。

ctlOf(int rs, int wc)方法:参数rs表示runState,参数wc表示workerCount,即根据runState和workerCount打包合并成ctl。

四、七大参数

corePoolSize:核心线程数
maximumPoolSize:最大线程数
keepAliveTime:空闲时存活时间
unit:存活时间单位
workQueue:队列
threadFactory:线程工程
handler:拒绝策略

五、四大拒绝策略

策略1:

ThreadPoolExecutor.AbortPolicy(),中止策略,将抛出 RejectedExecutionException。默认的情况下就是这种策略;

/**
     * A handler for rejected tasks that throws a
     * {@code RejectedExecutionException}.
     抛出{@code RejectedExecutionException}的拒绝任务处理程序
     */
    public static class AbortPolicy implements RejectedExecutionHandler {
        /**
         * Creates an {@code AbortPolicy}.
         */
        public AbortPolicy() { }

        /**
         * Always throws RejectedExecutionException.
         *
         * @param r the runnable task requested to be executed
         * @param e the executor attempting to execute this task
         * @throws RejectedExecutionException always
         */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            throw new RejectedExecutionException("Task " + r.toString() +
                                                 " rejected from " +
                                                 e.toString());
        }
    }
策略2:

ThreadPoolExecutor.CallerRunsPolicy()

CallerRunsPolicy从字面意思是调用者执行策略,也就是有主线程执行该任务;

/**
     * A handler for rejected tasks that runs the rejected task
     * directly in the calling thread of the {@code execute} method,
     * unless the executor has been shut down, in which case the task
     * is discarded.
     处理被拒绝任务的处理程序,直接在{@code execute}方法的调用线程中运行被拒绝任务,除非执行器已关闭,在这种情况下,任务被丢弃
     */
    public static class CallerRunsPolicy implements RejectedExecutionHandler {
        /**
         * Creates a {@code CallerRunsPolicy}.
         */
        public CallerRunsPolicy() { }

        /**
         * Executes task r in the caller's thread, unless the executor
         * has been shut down, in which case the task is discarded.
         *
         * @param r the runnable task requested to be executed
         * @param e the executor attempting to execute this task
         */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                r.run();
            }
        }
    }
策略3:

ThreadPoolExecutor.DiscardOldestPolicy()

处理被拒绝任务的处理程序,它丢弃最旧的未处理请求,然后重试{@code execute},除非执行器(主线程)被关闭,在这种情况下,该任务将被丢弃

 /**
     * A handler for rejected tasks that discards the oldest unhandled
     * request and then retries {@code execute}, unless the executor
     * is shut down, in which case the task is discarded.
     处理被拒绝任务的处理程序,它丢弃最旧的未处理请求,然后重试{@code execute},除非执行器(主线程)被关闭,在这种情况下,该任务将被丢弃。
     */
    public static class DiscardOldestPolicy implements RejectedExecutionHandler {
        /**
         * Creates a {@code DiscardOldestPolicy} for the given executor.
         */
        public DiscardOldestPolicy() { }

        /**
         * Obtains and ignores the next task that the executor
         * would otherwise execute, if one is immediately available,
         * and then retries execution of task r, unless the executor
         * is shut down, in which case task r is instead discarded.
         *
         * @param r the runnable task requested to be executed
         * @param e the executor attempting to execute this task
         */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                e.getQueue().poll();
                e.execute(r);
            }
        }
    }
策略4:

ThreadPoolExecutor.DiscardPolicy

丢弃策略。无法执行的任务将被简单地删除,与策略1不同,不抛出异常。

/**
     * A handler for rejected tasks that silently 			discards the
     * rejected task.
     *拒绝任务的处理程序,静默丢弃拒绝任务(即系不抛出异常)
     */
    public static class DiscardPolicy implements RejectedExecutionHandler {
        /**
         * Creates a {@code DiscardPolicy}.
         */
        public DiscardPolicy() { }

        /**
         * Does nothing, which has the effect of discarding task r.
         *
         * @param r the runnable task requested to be executed
         * @param e the executor attempting to execute this task
         */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值