线程池四种拒绝策略(ThreadPoolExecutor 内置)
线程池四种拒绝策略ThreadPoolExecutor 内置当满足线程池饱和条件时触发拒绝核心线程全部繁忙阻塞队列已满最大线程数已达到上限此时新提交任务会走拒绝策略JDK 内置 4 种实现。前置基础构造示意// 核心线程2最大5队列容量3空闲线程存活0sThreadPoolExecutorexecutornewThreadPoolExecutor(2,5,0L,TimeUnit.MILLISECONDS,newArrayBlockingQueue(3));// 设置拒绝策略executor.setRejectedExecutionHandler(newThreadPoolExecutor.CallerRunsPolicy());饱和临界点同时提交超过maxPoolSize queueSize 538个任务第9个开始触发拒绝策略。1. AbortPolicy默认策略直接抛出异常代码executor.setRejectedExecutionHandler(newThreadPoolExecutor.AbortPolicy());行为直接抛出RejectedExecutionException中断当前任务提交不执行任务。示例for(inti0;i10;i){executor.submit(()-{try{Thread.sleep(10000);}catch(InterruptedExceptione){e.printStackTrace();}});}提交第9个任务直接抛异常程序不捕获会中断业务流程。使用场景任务不允许丢失且调用方必须感知失败、主动降级重试同步阻塞业务、支付、核心数据处理不允许静默丢失任务小型同步接口任务量可控异常统一捕获做告警/重试。2. DiscardPolicy丢弃当前新任务无任何提示代码executor.setRejectedExecutionHandler(newThreadPoolExecutor.DiscardPolicy());行为默默丢掉新来的任务不抛异常、无日志、无告警调用方无感知。风险任务永久丢失业务数据缺失很难排查。使用场景非核心、可丢弃的统计上报、埋点日志、实时监控采集允许数据丢失、对一致性无要求的边缘辅助任务。3. DiscardOldestPolicy丢弃队列最老未执行任务执行新任务代码executor.setRejectedExecutionHandler(newThreadPoolExecutor.DiscardOldestPolicy());行为取出阻塞队列头部排队最久的任务丢弃再尝试提交当前新任务。使用场景实时数据、最新状态覆盖旧数据如设备实时状态上报、行情推送旧任务无保留价值最新数据才有效不需要历史排队任务。不适用场景订单、入库、消息消费等顺序/历史任务不能丢的业务。4. CallerRunsPolicy调用者线程执行你提问中的策略代码你给出的executor.setRejectedExecutionHandler(newThreadPoolExecutor.CallerRunsPolicy());行为不丢任务、不抛异常把当前任务交给提交任务的主线程同步执行。举例子主线程调用executor.submit()池子满了任务直接在主线程跑阻塞主线程直到任务完成。效果不会丢失任何任务提交线程被阻塞天然限流减缓任务提交速度给线程池留出时间处理堆积。示例演示ThreadPoolExecutorexecutornewThreadPoolExecutor(2,5,0L,TimeUnit.MILLISECONDS,newArrayBlockingQueue(3),newThreadPoolExecutor.CallerRunsPolicy());// 模拟10个长耗时任务for(inti0;i10;i){inttaskIdi;System.out.println(提交任务taskId 提交线程Thread.currentThread().getName());executor.submit(()-{System.out.println(执行任务taskId 执行线程Thread.currentThread().getName());try{Thread.sleep(3000);}catch(InterruptedExceptione){}});}输出现象前8个由池内线程执行第9、10个任务打印执行线程为main主线程同步执行。使用场景流量削峰、不允许丢任务文件同步、数据库批量入库、定时采集任务你项目采集接口非常适配无独立重试机制、任务丢失会造成业务数据缺失接口流量突增时自动降级为调用线程执行起到限流保护线程池Spring 内置定时池、普通业务异步线程池常用该策略。缺点高并发下主线程阻塞接口响应时间变长吞吐量下降。四种策略对比表策略处理逻辑是否丢任务是否抛异常典型适用场景AbortPolicy抛异常拒绝丢当前任务是核心交易、需感知失败的同步业务DiscardPolicy静默丢弃新任务丢当前任务否非核心埋点、监控日志DiscardOldestPolicy丢弃队列最老任务丢旧任务否实时状态、行情推送CallerRunsPolicy调用线程同步执行不丢失否数据采集、入库、定时任务、流量削峰生产使用建议结合你项目采集定时任务你的业务是http采集定时任务推荐CallerRunsPolicy采集数据不能丢丢弃会造成数据断层池子打满时主线程同步执行自动限流避免无限创建任务OOM无需额外编写重试、丢失补偿逻辑。拓展自定义拒绝策略生产常用兜底内置策略无法满足告警需求时自定义打印日志推送告警publicclassCustomRejectHandlerimplementsRejectedExecutionHandler{OverridepublicvoidrejectedExecution(Runnabler,ThreadPoolExecutorexecutor){log.error(线程池饱和任务被拒绝核心:{},最大:{},队列容量:{},executor.getCorePoolSize(),executor.getMaximumPoolSize(),executor.getQueue().size());// 推送钉钉/短信告警// 可选本地持久化任务后续补偿thrownewRuntimeException(任务提交失败线程池已满);}}