设为首页 加入收藏

TOP

jdk线程池ThreadPoolExecutor优雅停止原理解析(自己动手实现线程池)(二)(二)
2023-07-25 21:33:13 】 浏览:161
Tags:jdk 程池 ThreadPoolExecutor 解析
0 private static final int TERMINATED = 3 << COUNT_BITS; private static int runStateOf(int c) { return c & ~CAPACITY; } private static int ctlOf(int rs, int wc) { return rs | wc; } private static boolean runStateLessThan(int c, int s) { return c < s; } private static boolean runStateAtLeast(int c, int s) { return c >= s; } private static boolean isRunning(int c) { return c < SHUTDOWN; } /** * 推进线程池工作状态 * */ private void advanceRunState(int targetState) { for(;;){ // 获得当前的线程池状态 int currentCtl = this.ctl.get(); // 1 (runState >= targetState)如果当前线程池状态不比传入的targetState小 // 代表当前状态已经比参数要制定的更加快(或者至少已经处于对应阶段了),则无需更新poolStatus的状态(或语句中第一个条件为false,直接break了) // 2 (this.ctl.compareAndSet),cas的将runState更新为targetState // 如果返回true则说明cas更新成功直接break结束(或语句中第一个条件为false,第二个条件为true) // 如果返回false说明cas争抢失败,再次进入while循环重试(或语句中第一个和第二个条件都是false,不break而是继续执行循环重试) if (runStateAtLeast(currentCtl, targetState) || this.ctl.compareAndSet( currentCtl, ctlOf(targetState, workerCountOf(currentCtl) ))) { break; } } } }
  • 因为线程池状态不是单独存放,而是放在ctl这一32位数据的高3位的,读写都比较麻烦,因此提供了runStateOf和ctlOf等辅助方法(位运算)来简化操作。
  • 线程池的状态是单调递进的,由于巧妙的将状态靠前的值设置的更小,因此通过直接比较状态的值来判断当前线程池状态是否推进到了指定的状态(runStateLessThan、runStateAtLeast、isRunning、advanceRunState)。

jdk线程池ThreadPoolExecutor优雅停止具体实现原理

线程池的优雅停止一般要能做到以下几点:

  1. 线程池在中止后不能再受理新的任务
  2. 线程池中止的过程中,已经提交的现存任务不能丢失(等待剩余任务执行完再关闭或者能够把剩余的任务吐出来还给用户)
  3. 线程池最终关闭前,确保创建的所有工作线程都已退出,不会出现资源的泄露

下面我们从源码层面解析ThreadPoolExecutor,看看其是如何实现上述这三点的.

如何中止线程池

ThreadPoolExecutor线程池提供了shutdown和shutdownNow这两个public方法给使用者用于发出线程池的停止指令。

shutdown方法

shutdown方法用于关闭线程池,并令线程池从RUNNING状态转变位SHUTDOWN状态。位于SHUTDOWN状态的线程池,不再接收新任务,但已提交的任务会全部被执行完。

    /**
     * 关闭线程池(不再接收新任务,但已提交的任务会全部被执行)
     * 但不会等待任务彻底的执行完成(awaitTermination)
     */
    public void shutdown() {
        final ReentrantLock mainLock = this.mainLock;

        // shutdown操作中涉及大量的资源访问和更新,直接通过互斥锁防并发
        mainLock.lock();
        try {
            // 用于shutdown/shutdownNow时的安全访问权限
            checkShutdownAccess();
            // 将线程池状态从RUNNING推进到SHUTDOWN
            advanceRunState(SHUTDOWN);
            // shutdown不会立即停止所有线程,而仅仅先中断idle状态的多余线程进行回收,还在执行任务的线程就慢慢等其执行完
            interruptIdleWorkers();
            // 单独为ScheduledThreadPoolExecutor开的一个钩子函数(hook for ScheduledThreadPoolExecutor)
            onShutdown();
        } finally {
            mainLock.unlock();
        }

        // 尝试终止线程池
        tryTerminate();
    }

    /**
     * 用于shutdown/shutdownNow时的安全访问权限
     * 检查当前调用者是否有权限去通过interrupt方法去中断对应工作线程
     * */
    private void checkShutdownAccess() {
        // 判断jvm启动时是否设置了安全管理器SecurityManager
        SecurityManager security = System.getSecurityManager();
        // 如果没有设置,直接返回无事发生

        if (security != null) {
            // 设置了权限管理器,验证当前调用者是否有modifyThread的权限
            // 如果没有,checkPermission会抛出SecurityException异常
            security.checkPermission(shutdownPerm);
    
            // 通过上述校验,检查工作线程是否能够被调用者访问
            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
                for (MyWorker w : workers) {
                    // 检查每一个工作线程中的thread对象是否有权限被调用者访问
                    security.checkAccess(w.thread);
                }
            } finally {
                mainLock.unlock();
            }
        }
    }

    /**
     * 中断所有处于idle状态的线程
     * */
    private void interruptIdleWorkers() {
        // 默认打断所有idle状态的工作线程
        interruptIdleWorkers(false);
    }

    private static final boolean ONLY_ONE = true;

    /**
     * 中断处于idle状态的线程
     * @param onlyOne 如果为ture,至多只中断一个工作线程(可能一个都不中断)
     *                如果为false,中断workers内注册的所有工作线程
     * */
    private void interruptIdleWorkers(boolean onlyOne) {
        final ReentrantLock mainLock = this.
首页 上一页 1 2 3 4 5 6 7 下一页 尾页 2/7/7
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇数据库可视化工具分享 (DBeaver) 下一篇Spring AOP中增强Advice的执行顺序

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目