线程池原理

一、什么是线程池

线程池是一种池化技术,用于预先创建并管理一组线程,避免频繁创建和销毁线程的开销,提高性能和响应速度。它的七大核心参数包括:核心线程数最大线程数空闲存活时间单位时间任务队列线程工厂拒绝策略

  1. corePoolSize:核心线程数,即线程池中始终保持的线程数量。

  2. maximumPoolSize:最大线程数,即线程池中允许的最大线程数量。

  3. keepAliveTime:线程空闲时间,超过这个时间的非核心线程会被销毁。

  4. workQueue:任务队列,存放待执行的任务。

  5. hreadFactory:线程工厂,用于创建新线程。

  6. rejectedExecutionHandler:任务拒绝处理器,当任务无法执行时的处理策略。

二、工作原理

  1. 默认情况下线程不会预创建,任务提交之后才会创建线程(可以通过设置 prestartAllCoreThreads 预创建核心线程)。

  2. 当核心线程满了之后不会新建线程,而是把任务堆积到任务队列中。

  3. 如果任务队列放不下了,然后才会新增线程,直至达到最大线程数。

  4. 如果任务队列满了,然后也已经达到最大线程数了,这时候来任务会执行拒绝策略。

  5. 如果线程空闲时间超过空闲存活时间,并且当前线程数大于核心线程数的则会销毁线程,直到线程数等于核心线程数(设置 allowCoreThreadTimeOut 为 true 可以回收核心线程,默认为 false)。

图解:
  1. 任务提交,线程池线程数还未达到核心线程数:

  2. 核心线程数已满,任务队列未满的情况:

  3. 核心线程数已满,任务队列已满的情况:

  4. 线程池中线程数已达最大线程数的情况:

注意核心线程和非核心线程在线程池中是一样的,并没有特殊的标识区分!

三、任务队列

队列类型行为适用场景
LinkedBlockingQueue无界或有界队列,FIFO 顺序固定大小的线程池(如 FixedThreadPool
ArrayBlockingQueue有界队列,FIFO 顺序,需指定容量控制任务积压,避免资源耗尽
SynchronousQueue不存储任务,直接将任务交给线程。若无线程可用,则创建新线程或拒绝任务高吞吐、任务处理快的场景(如 CachedThreadPool
PriorityBlockingQueue按优先级排序的无界队列需要任务优先级调度的场景
DelayQueue存储延迟任务,任务按到期时间排序定时任务或延迟任务调度

四、拒绝策略

策略行为适用场景
AbortPolicy(默认)直接抛出异常需要严格保证任务不丢失
CallerRunsPolicy用提交任务的线程执行允许降级执行,避免任务堆积
DiscardPolicy静默丢弃可容忍任务丢失
DiscardOldestPolicy丢弃队列最旧任务优先处理新任务
源码分析
  1. AbortPolicy

    // 定义一个静态内部类 AbortPolicy,实现拒绝任务处理策略
    public static class AbortPolicy implements RejectedExecutionHandler {
        
        /**
         * 默认构造方法,无特殊初始化逻辑
         * 该策略实例化时不需要任何参数或状态设置
         */
        public AbortPolicy() { 
            // 空构造器,因为该策略无需维护内部状态
        }
    
        /**
         * 当线程池无法接受新任务时,直接抛出 RejectedExecutionException
         * 这是标准的"中止策略"实现,强制调用方处理任务被拒绝的情况
         *
         * @param r 被拒绝执行的任务对象(Runnable)
         * @param e 触发拒绝操作的线程池实例(ThreadPoolExecutor)
         * @throws RejectedExecutionException 始终抛出,包含任务和线程池的详细信息
         * 
         * 实现细节:
         * - 使用 throw 立即中断执行流程
         * - 异常信息包含被拒任务的 toString() 和线程池的 toString()
         * - 适用于需要严格处理任务提交失败的场景
         * - 相比其他策略(如静默丢弃),更有利于问题排查
         */
        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            throw new RejectedExecutionException("Task " + r.toString() +
                                                 " rejected from " +
                                                 e.toString());
            // 注意:
            // 1. 需要确保调用方有异常处理机制
            // 2. 任务对象的 toString() 应实现有意义的描述
            // 3. 线程池的 toString() 通常包含状态信息(如 poolSize, activeCount 等)
        }
    }
  2. CallerRunsPolicy

    // 定义静态内部类 CallerRunsPolicy,实现一种温和的拒绝策略
    public static class CallerRunsPolicy implements RejectedExecutionHandler {
        
        /**
         * 默认构造方法,无需特殊初始化
         * 该策略不依赖任何内部状态
         */
        public CallerRunsPolicy() { 
            // 空构造器,符合无状态设计
        }
    
        /**
         * 当线程池无法接受新任务时,由调用者线程直接执行任务
         * 这是一种流量整形机制,通过降低任务提交速度保护系统
         *
         * @param r 被拒绝执行的任务对象
         * @param e 触发拒绝操作的线程池实例
         * 
         * 关键逻辑:
         * 1. 检查线程池是否处于SHUTDOWN状态(避免执行已关闭池的任务)
         * 2. 若线程池仍活跃,则用当前提交线程同步执行任务
         * 3. 实际效果相当于将线程池的"提交线程"临时转变为"工作线程"
         */
        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            // 防御性检查:确保线程池未关闭
            if (!e.isShutdown()) {
                // 关键行为:直接在调用者线程执行任务(同步阻塞)
                r.run();
                
                // 注意:
                // - 此处调用的是 run() 而非 start(),意味着同步执行
                // - 可能导致提交线程(如主线程/网络IO线程)阻塞
                // - 适用于能接受短时阻塞的任务场景
            }
            // 若线程池已关闭,则静默丢弃任务(符合线程池生命周期规范)
        }
    }
  3. DiscardPolicy

    // 定义静态内部类 DiscardPolicy,实现静默丢弃任务的拒绝策略
    public static class DiscardPolicy implements RejectedExecutionHandler {
        
        /**
         * 默认构造方法,无状态初始化
         * 该策略不需要任何配置参数
         */
        public DiscardPolicy() {
            // 空构造器符合无状态设计原则
        }
    
        /**
         * 当线程池无法接受新任务时,直接丢弃被拒绝的任务
         * 该策略不会给出任何通知或反馈,属于静默失败模式
         *
         * @param r 被拒绝的任务对象(Runnable)
         * @param e 触发拒绝操作的线程池实例(ThreadPoolExecutor)
         * 
         * 实现特点:
         * - 方法体为空,不执行任何操作
         * - 不检查线程池状态(即使线程池未关闭也直接丢弃)
         * - 适用于允许任务丢失的非关键场景
         * 
         * 风险提示:
         * - 任务丢失可能导致业务逻辑不完整
         * - 无日志记录,问题排查困难
         */
        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            // 空实现:被拒绝的任务直接被丢弃
            // 注意:此处没有调用r.run()也没有抛出异常
        }
    }
  4. DiscardOldestPolicy

    // 定义静态内部类 DiscardOldestPolicy,实现丢弃队列最旧任务的拒绝策略
    public static class DiscardOldestPolicy implements RejectedExecutionHandler {
        
        /**
         * 默认构造方法,无需特殊初始化
         * 策略本身不维护内部状态
         */
        public DiscardOldestPolicy() {
            // 空构造器符合无状态设计
        }
    
        /**
         * 当线程池无法接受新任务时,丢弃工作队列中的最旧任务并重试提交新任务
         * 该策略实现了任务队列的滚动更新机制
         *
         * @param r 当前被拒绝的任务对象
         * @param e 触发拒绝操作的线程池实例
         * 
         * 核心逻辑:
         * 1. 检查线程池是否处于SHUTDOWN状态(防御性编程)
         * 2. 从工作队列头部移除一个任务(FIFO策略)
         * 3. 尝试重新提交当前任务(可能成功或再次触发拒绝策略)
         * 
         * 注意事项:
         * - 队列类型影响行为(对PriorityQueue等特殊队列可能不符合预期)
         * - 存在任务饥饿风险(持续提交可能导致旧任务永远无法执行)
         */
        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                // 移除队列头部元素(最旧任务)
                e.getQueue().poll();  // 注意:此处使用非阻塞的poll()
                
                // 尝试重新提交当前任务(可能成功或再次触发拒绝策略)
                e.execute(r);
                
                /* 潜在问题:
                 * 1. 当队列持续满载时,可能进入【丢弃旧任务->提交新任务->再次被拒】的死循环
                 * 2. 被丢弃的任务不会得到任何通知(需确保业务容忍数据丢失)
                 * 3. 多线程竞争环境下可能产生非公平调度
                 */
            }
        }
    }

五、常见线程池实现方式

实现方式描述适用场景
FixedThreadPool创建一个固定数量的线程池。线程池中的线程数是固定的,空闲的线程会被复用。如果所有线程都在忙,则新任务会放入队列中等待适合负载稳定的场景,任务数量确定且不需要动态调整线程数
CachedThreadPool一个可以根据需要创建新线程的线程池。线程池的线程数量没有上限,空闲线程会在 60 秒后被回收,如果有新任务且没有可用线程,会创建新线程适合短期大量并发任务的场景,任务执行时间短且线程数需求变化较大。
SingleThreadExecutor创建一个只有单个线程的线程池。只有一个线程处理任务,任务会按照提交顺序依次执行适用于需要保证任务按顺序执行的场景,或者不需要并发处理任务的情况
ScheduledThreadPool支持定时任务和周期性任务的线程池。可以定时或以固定频率执行任务,线程池大小可以由用户指定适用于需要周期性任务执行的场景,如定时任务调度器
WorkStealingPool基于任务窃取算法的线程池。线程池中的每个线程维护一个双端队列(deque),线程可以从自己的队列中取任务执行。如果线程的任务队列为空,它可以从其他线程的队列中“窃取”任务来执行,达到负载均衡的效果适合大量小任务并行执行,特别是递归算法或大任务分解成小任务的场景
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值