页面加载中
博客快捷键
按住 Shift 键查看可用快捷键
ShiftK
开启/关闭快捷键功能
ShiftA
打开/关闭中控台
ShiftD
深色/浅色显示模式
ShiftS
站内搜索
ShiftR
随机访问
ShiftH
返回首页
ShiftL
友链页面
ShiftP
关于本站
ShiftI
原版/本站右键菜单
松开 Shift 键或点击外部区域关闭
互动
最近评论
暂无评论
标签
寻找感兴趣的领域
暂无标签
    0
    文章
    0
    标签
    8
    分类
    10
    评论
    128
    功能
    深色模式
    标签
    JavaScript12TypeScript8React15Next.js6Vue10Node.js7CSS5前端20
    互动
    最近评论
    暂无评论
    标签
    寻找感兴趣的领域
    暂无标签
      0
      文章
      0
      标签
      8
      分类
      10
      评论
      128
      功能
      深色模式
      标签
      JavaScript12TypeScript8React15Next.js6Vue10Node.js7CSS5前端20
      未知歌曲
      未播放
      ♪ 暂无歌词 ♪
      随便逛逛
      博客分类
      文章标签
      复制地址
      深色模式
      AnHeYuAnHeYu
      Search⌘K
      博客
        暂无其他文档

        线程池(二)ThreadPoolExector

        本文详解 Java 线程池核心类 ThreadPoolExecutor,涵盖其构造函数、七大核心参数(核心线程数、最大线程数、空闲时间、任务队列、线程工厂、拒绝策略)、任务执行流程、五种运行状态及源码分析,帮助开发者合理配置线程池以提升应用性能。

        July 2, 20248 分钟 阅读3 次阅读

        有的时候博客内容会有变动,首发博客是最新的,其他博客地址可能会未同步,认准https://blog.zysicyj.top

        可点击链接https://blog-1253652709.cos.ap-guangzhou.myqcloud.com//picgo/202401180921373.png 解答疑问

        线程池执行器 (ThreadPoolExecutor) 详解

        目录

        1. 简介
        2. ThreadPoolExecutor 构造函数
        3. 核心参数
        4. 执行任务流程
        5. 线程池的状态
        6. 源码分析
        7. 应用场景
        8. 注意事项

        简介

        ThreadPoolExecutor 是 Java 中用于管理线程池的核心类。它提供了一种灵活而强大的机制来创建和管理线程池,允许我们通过线程池来控制并发任务的执行。通过合理地配置和使用线程池,我们可以显著提升应用程序的性能和响应能力。

        ThreadPoolExecutor 构造函数

        ThreadPoolExecutor 提供了多种构造函数,最常用的是如下这个:

        public ThreadPoolExecutor(
            int corePoolSize,
            int maximumPoolSize,
            long keepAliveTime,
            TimeUnit unit,
            BlockingQueue<Runnable> workQueue,
            ThreadFactory threadFactory,
            RejectedExecutionHandler handler)
        

        参数解析: - corePoolSize: 核心线程数,线程池中始终保持活动的线程数。 - maximumPoolSize: 最大线程数,线程池中允许的最大线程数。 - keepAliveTime: 线程空闲时间,当线程数大于 corePoolSize 时,多余的空闲线程存活的时间。 - unit: 时间单位,用于指定 keepAliveTime 的时间单位。 - workQueue: 任务队列,用于存放待执行的任务。 - threadFactory: 线程工厂,用于创建新线程。 - handler: 拒绝策略,当任务无法提交到线程池时的处理方式。

        核心参数

        1. corePoolSize 和 maximumPoolSize:

          • 核心线程数 (corePoolSize) 是线程池中保持活跃的线程数,即使这些线程处于空闲状态也不会被销毁。
          • 最大线程数 (maximumPoolSize) 是线程池中允许的最大线程数,当队列中的任务满了且当前线程数小于 maximumPoolSize 时,线程池会创建新的线程来执行任务。
        2. keepAliveTime 和 unit:

          • 空闲时间 (keepAliveTime) 是当线程数超过 corePoolSize 时,多余的空闲线程的存活时间,超过这个时间,空闲线程会被销毁。
          • 时间单位 (unit) 是一个 TimeUnit 枚举,用于指定 keepAliveTime 的时间单位。
        3. workQueue:

          • 任务队列 (workQueue) 是一个阻塞队列,用于存放待执行的任务。常用的阻塞队列包括 ArrayBlockingQueue, LinkedBlockingQueue, SynchronousQueue 等。
        4. threadFactory:

          • 线程工厂 (threadFactory) 用于创建线程,一般可以通过自定义 ThreadFactory 来设置线程的名称、优先级等属性。
        5. handler:

          • 拒绝策略 (RejectedExecutionHandler) 当线程池和队列都满了,再有任务提交时的处理策略。Java 提供了四种默认的拒绝策略:
            • AbortPolicy: 抛出 RejectedExecutionException。
            • CallerRunsPolicy: 由调用线程处理该任务。
            • DiscardPolicy: 丢弃任务,不予处理。
            • DiscardOldestPolicy: 丢弃队列中最旧的任务,然后尝试提交新任务。

        执行任务流程

        当一个任务提交到线程池时,ThreadPoolExecutor 会按以下步骤进行处理: 1. 如果线程池中的线程数小于 corePoolSize,即使有空闲线程,也会创建一个新线程来执行新任务。 2. 如果线程池中的线程数达到或超过 corePoolSize,新任务会被添加到工作队列中。 3. 如果工作队列已满,且线程数小于 maximumPoolSize,会创建新的线程来执行任务。 4. 如果线程数达到 maximumPoolSize 且工作队列已满,会根据拒绝策略处理新任务。

        线程池的状态

        线程池在运行过程中会有以下几种状态: - RUNNING: 接受新任务并处理队列中的任务。 - SHUTDOWN: 不接受新任务,但会处理队列中的任务。 - STOP: 不接受新任务,也不处理队列中的任务,并中断正在执行的任务。 - TIDYING: 所有任务都已终止,工作线程数为 0,线程池进入该状态并将运行 terminated() 钩子方法。 - TERMINATED: terminated() 方法执行完成。

        源码分析

        接下来我们深入分析 ThreadPoolExecutor 的核心源码,了解其内部工作机制。

        任务提交

        任务提交的方法有 execute(Runnable command) 和 submit(Callable<T> task)。以下是 execute 方法的部分源码:

        public void execute(Runnable command) {
            if (command == null)
                throw new NullPointerException();
            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);
        }
        

        该方法分为三个步骤: 1. 尝试创建核心线程:如果当前线程数小于 corePoolSize,尝试创建一个新的线程来执行任务。 2. 任务入队列:如果线程数已达到 corePoolSize,将任务加入工作队列。 3. 创建非核心线程:如果队列已满且线程数小于 maximumPoolSize,创建新的线程。如果线程数已达到 maximumPoolSize,执行拒绝策略。

        应用场景

        ThreadPoolExecutor 在以下场景中非常有用: - Web 服务器:处理大量并发请求,避免因频繁创建和销毁线程带来的开销。 - 后台任务:执行异步任务,如日志处理、数据备份等。 - 定时任务:结合 ScheduledThreadPoolExecutor,可以定时或周期性地执行任务。

        注意事项

        1. 合理配置线程池参数:过大的线程池会导致资源浪费,过小的线程池则无法充分利用系统资源。
        2. 选择合适的任务队列:不同类型的任务队列适用于不同的场景,需要根据实际需求选择合适的队列。
        3. 处理异常情况:要处理好线程池中的异常情况,避免线程意外中断导致任务丢失。
        4. 监控线程池状态:可以通过 ThreadPoolExecutor 提供的 getPoolSize()、getActiveCount()、getCompletedTaskCount() 等方法监控线程池的运行状态。

        通过深入理解和合理配置 ThreadPoolExecutor,我们可以在实际项目中高效地管理并发任务,提升应用的性能和稳定性。

        最后更新于 July 2, 2024
        On this page
        暂无目录