ThreadPoolExecutor线程池

一、线程池状态控制

        使用AtomicInteger变量将工作线程数量与运行状态压缩在一起【其中高3位为线程池的运行状态,低29位为当前工作线程数】

        运行状态

                RUNNING:运行状态,可以处理新任务并执行队列中的任务【高三位为111】

                SHUTDOWN:关闭状态,不接受新任务但是执行队列中的任务【高三位为000】

                STOP:停止状态,不接受新任务也不处理队列中的任务并且会打断当前运行中任务【高三位为001】

                TIDYING:整理状态,所有任务结束并且此时工作线程为0会进入结束状态【高三位为010】

                TERMINATED:结束状态【高三位为011】

二、内部方法原理分析

构造方法

    new ThreadPoolExecutor(
                int corePoolSize,
                int maximumPoolSize,
                long keepAliveTime,
                TimeUnit unit,
                BlockingQueue<Runnable> workQueue,
                ThreadFactory threadFactory,
                RejectedExecutionHandler handler),这是参数最全的构造方式也是推荐使用的构造方式,因此必须熟悉每一个参数的含义

        corePoolSize:核心线程数,线程池的基本大小

        maximumPoolSize:线程池最大数量,线程池允许创建的最大线程数【如果是无界队列,此参数意义不大】

        keepAliveTime:线程空闲时最大存活时间

        unit:keepAliveTime时间类型

        BlockingQueue:用于保存等待执行的任务的阻塞队列,一般可以使用下面几种

                ArrayBlockingQueue:基于数组实现的有界阻塞队列,FIFO(先进先出)对元素进行排序

                LinkedBlockingQueue:一个基于链表实现的阻塞队列,不设置容量则为无界队列,FIFO(先进先出)对元素进行排序,吞吐量高

                SynchrousQueue:一个不存储元素的阻塞队列,每个插入元素都必须等到另一个线程调用移出操作,否则插入操作会一直阻塞[相反也是],吞吐量高

                PriorityBlockingQueue:优先级阻塞队列

                还有很多拓展的队列,在JCTools中可以学习

        threadFactory:用于设置创建线程的工厂

        RejectedExecutionHandler:饱和策略,当线程池中的线程数超过线程池最大数量执行的拒绝策略

                AbortPolicy:直接抛出异常

                CallerRunsPolicy:直接调用所在线程执行任务

                DiscardOldestPolicy:丢弃队列中最近的一个任务,并执行当前任务

                DisacrdPolicy:不处理直接丢弃

                自定义策略:实现RejectedExecutionHandler

往线程池中提交任务

execute方法执行逻辑

        execute(Runnable command):向线程池提交任务

        工作流程

                1、判断当前线程池中的工作线程数与corePoolSize的大小,如果比corePoolSize小,会创建一个新的线程用于执行任务,否则进入下一步

                2、判断当前线程池中的任务队列是否已塞满,如果没有塞满直接将任务扔进队列中,否则进入下一步

                3、判断当前线程池中的工作线程数是否达到了maximumPoolSize,未达到创建非核心线程执行任务,否则根据饱和策略处理

public void execute(Runnable command) {
    if (command == null){
        throw new NullPointerException();
    }
    // 这个值包含了线程池的状态以及当前线程池中工作线程的个数【使用ctl进行判断是必须先get防止并发问题】
    int c = ctl.get();
    // 如果工作线程数 < 核心线程数
    if (workerCountOf(c) < corePoolSize) {
        // 新建一个工作线程来运行任务,如果成功了,则直接返回【此过程会获取全局锁会消耗性能,因此线程池有个优化点,可以预热线程池,直接在启动时先创建线程(prestartAllCoreThreads)】
        if (addWorker(command, true)){
            return;
        }
        // 线程池已经shutdown,shutdown的线程池不再接收新任务
        // workerCountOf(c) < corePoolSize判断后,由于并发别的线程先创建了worker线程,导致workerCount>=corePoolSize
        // 获取当前线程池的状态【每次一旦需要进行线程池状态判断都需要先get】
        c = ctl.get();
    }
    // RUNNING状态,则尝试把任务添加到任务队列
    if (isRunning(c) && workQueue.offer(command)) {
        // 重新检查
        int recheck = ctl.get();
        // 如果线程池已经不是running状态了,应该拒绝添加新任务,从workQueue中删除任务
        if (!isRunning(recheck) && remove(command)){
            // 拒绝任务
            reject(command);
        }
        // 如果线程池是运行状态,或者从workQueue中删除任务失败(刚好有一个线程执行完毕,并消耗了这个任务),确保还有线程执行任务(只要有一个就够了)
        else if (workerCountOf(recheck) == 0){
            // 添加非核心线程
            addWorker(null, false);
        }
    }
    // 创建非核心线程来执行任务
    else if (!addWorker(command, false)){
        reject(command);
    }
}

添加新的线程

addWorker方法流程

        addWorker(Runnable command,boolean core):根据core值判断创建的是核心线程还是非核心线程

        addWorker的工作可分为两个部分

                1、原子操作,判断是否可以创建worker,通过自旋、CAS等操作判断继续创建还是返回false,自旋周期一般很短[比锁效率高]

                2、创建Worker启动线程执行任务

private boolean addWorker(Runnable firstTask, boolean core) {
    retry:
    // 无限循环
    for (;;) {
        // 这个值包含了线程池的状态以及当前线程池中工作线程的个数
        int c = ctl.get();
        // 获取线程池的状态值
        int rs = runStateOf(c);
        // 线程池的state越小越是运行状态,runnbale=-1,shutdown=0,stop=1,tidying=2,terminated=3
        // 如果线程池state已经至少是shutdown状态了
        // rs == SHUTDOWN(隐含:rs>=SHUTDOWN)false情况:线程池状态已经超过shutdown,可能是stop、tidying、terminated其中一个,即线程池已经终止
        // firstTask == null(隐含:rs==SHUTDOWN)false情况:firstTask不为空,rs==SHUTDOWN且firstTask不为空,return false,场景是在线程池已经shutdown后,还要添加新的任务,拒绝
        // !workQueue.isEmpty()(隐含:rs==SHUTDOWN,firstTask==null)false情况:workQueue为空,当firstTask为空时是为了创建一个没有任务的线程,再从workQueue中获取任务,如果workQueue已经为空,那么就没有添加新worker线程的必要了
        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;
            }
            // 如果原子性增加工作线程数(+1)成功,代表创建线程成功
            if (compareAndIncrementWorkerCount(c)){
                break retry;
            }
            // 再次获取判断线程池状态
            c = ctl.get();
            if (runStateOf(c) != rs){
                continue retry;
            }
        }
    }
    boolean workerStarted = false;
    boolean workerAdded = false;
    Worker w = null;
    try {
        // 创建Worker
        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());
                // 运行中状态或者shutdown状态但是任务为null代表可能队列中还有任务
                if (rs < SHUTDOWN || (rs == SHUTDOWN && firstTask == null)) {
                    // 线程正在运行
                    if (t.isAlive()){
                        throw new IllegalThreadStateException();
                    }
                    // 把worker加入到工作线程Set里面
                    workers.add(w);
                    int s = workers.size();
                    if (s > largestPoolSize){
                        largestPoolSize = s;
                    }
                    workerAdded = true;
                }
            } finally {
                mainLock.unlock();
            }
            if (workerAdded) {
                // 开始执行任务
                t.start();
                workerStarted = true;
            }
        }
    } finally {
        if (!workerStarted){
            // 失败处理
            addWorkerFailed(w);
        }
    }
    return workerStarted;
}

线程真正运行的地方

runWorker方法执行流程

        runWorker(Worker w):执行任务

final void runWorker(Worker w) {
    // 当前线程
    Thread wt = Thread.currentThread();
    // 任务
    Runnable task = w.firstTask;
    w.firstTask = null;
    // 可以响应中断【在任务执行前是可以中断的】
    w.unlock(); 
    boolean completedAbruptly = true;
    try {
        // 任务不为null,或者队列中还存在任务
        while (task != null || (task = getTask()) != null) {
            // 上锁防止执行中的线程在shutdown时被中断
            w.lock();
            // Stop状态下直接中断
            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 {
        // 处理退出后的worker
        processWorkerExit(w, completedAbruptly);
    }
}

获取需要被执行的task

getTask方法执行流程

        getTask():从队列中获取任务执行

private Runnable getTask() {
    // 是否超时
    boolean timedOut = false;
        for (;;) {
            // 用于判断当前线程池的状态
            int c = ctl.get();
            int rs = runStateOf(c);
            // 如果服务器状态为shutdown及以上
            // 如果服务器状态为Stop之上并且工作队列是空的,直接workerNo减1并且返回null
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                decrementWorkerCount();
                return null;
            }
            // 工作中的线程数
            int wc = workerCountOf(c);
            // 是否超时等待任务当大于核心线程数后
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
            // 比最大线程数大,或者超时等待并且超时
            // 工作线程数大于1或者任务队列为null
            if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
                if (compareAndDecrementWorkerCount(c))
                    return null;
                continue;
            }
            try {
                // 如果允许超时获取任务调用poll否则直接take
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take();
                if (r != null)
                    return r;
                // 代表已经超时
                timedOut = true;
            } catch (InterruptedException retry) {
                // 响应中断,重新开始,中断状态会被清除
                timedOut = false;
            }
        }
    }

worker线程退出

        processWorkerExit():处理worker线程退出

private void processWorkerExit(Worker w, boolean completedAbruptly) {
    // 如果是突然退出
    if (completedAbruptly)
        // worker线程数减1
        decrementWorkerCount();
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            // 把worker的完成任务数加到线程池的完成任务数
            completedTaskCount += w.completedTasks;
            // 工作者线程集合中移除
            workers.remove(w);
        } finally {
            mainLock.unlock();
        }
        // 判断线程池状态,尝试终止线程池
        tryTerminate();
        int c = ctl.get();
        // 如果线程池是Stop之下的状态
        if (runStateLessThan(c, STOP)) {
            // 非突然停止
            if (!completedAbruptly) {
                // 如果min为0,即不需要维持核心线程数量,且workQueue不为空,至少保持一个线程
                int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
                if (min == 0 && ! workQueue.isEmpty())
                    min = 1;
                // 如果线程数量大于最少数量,直接返回,否则下面至少要addWorker一个
                if (workerCountOf(c) >= min)
                    return;
            }
            // 添加一个没有firstTask的worker
            // 只要worker是completedAbruptly突然终止的,或者线程数量小于要维护的数量,就新添一个worker线程,即使是shutdown状态
            addWorker(null, false);
        }
    }
三、线程池带来的好处

        1、降低资源消耗,通过重复利用已创建的线程降低线程创建和销毁造成的消耗

        2、提高响应速度,当任务到达时不用等待线程创建就能执行任务

        3、提高线程的可管理性,线程是稀缺资源,如果无限制的创建不仅会消耗系统资源还会降低系统的稳定性

四、线程池类型

        1、FixedThreadPool:固定线程数线程池,特点核心线程池与最大线程池大小一样并且线程不会被回收,没有一个任务就会创建一个线程去执行直到到达最大线程数

        2、CachedThreadPool:缓存线程池,特点核心线程数为0,当有任务到来时会创建一个线程执行任务,如果存在空闲线程则不会创建,空闲线程超过60s会自动回收

        3、SingleThreadExecutor:只存在一个线程的线程池,特点核心线程池与最大线程池大小都为1并且线程不会被回收[保证了task按照指定顺序被执行]

        4、ScheduledThreadPoolExecutor:定时线程池,特点可以定时让线程执行任务

        5、WorkStealingPool:窃取式、抢占式线程池,特点通过线程并行实现,此线程不能保证任务的顺序执行

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值