MST
星途 面试题库

面试题:Java线程池有界队列满时的处理策略及原理

当Java线程池中的有界队列已满,且有新任务提交时,线程池有几种处理策略?请分别详细描述每种策略的实现原理,以及在不同应用场景下应如何选择合适的策略。
49.7万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试
  1. AbortPolicy(默认策略)
    • 实现原理:当有界队列已满且线程池达到最大线程数时,新提交的任务会被拒绝,并且抛出RejectedExecutionException异常。这是线程池默认的拒绝策略。例如在ThreadPoolExecutor类中,reject方法的默认实现就是使用AbortPolicy策略,如果任务无法被处理,就会抛出异常。
    • 应用场景:适用于对任务处理非常严格,不允许任务丢失的场景。比如在一些关键的金融交易系统中,如果交易任务被拒绝意味着交易可能失败,这种情况下可以通过捕获异常进行相应的处理,如记录日志、回滚交易等操作。
  2. CallerRunsPolicy
    • 实现原理:当有界队列已满且线程池达到最大线程数时,新提交的任务不会被拒绝,而是由提交任务的线程(调用者线程)来执行该任务。这样做的目的是减少新任务的提交速率,缓解线程池的压力。例如在ThreadPoolExecutor类的rejectedExecution方法中,如果使用CallerRunsPolicy策略,会直接在当前调用线程中执行任务r.run()
    • 应用场景:适用于对响应时间要求不高,但希望能尽可能处理提交任务的场景。比如在一些后台日志记录系统中,即使记录日志的任务偶尔由调用线程执行,也不会对系统的主要业务逻辑产生较大影响,同时能保证日志任务尽量不丢失。
  3. DiscardPolicy
    • 实现原理:当有界队列已满且线程池达到最大线程数时,新提交的任务会被直接丢弃,不会抛出任何异常。在ThreadPoolExecutor类中,如果使用DiscardPolicy策略,rejectedExecution方法只是简单地返回,不做任何其他处理,意味着新任务被丢弃。
    • 应用场景:适用于可以容忍任务丢失的场景。比如在一些实时统计系统中,对于一些时效性较强但不重要的统计数据采集任务,如果系统繁忙无法处理新任务,丢弃这些任务对整体统计结果影响不大。
  4. DiscardOldestPolicy
    • 实现原理:当有界队列已满且线程池达到最大线程数时,会丢弃队列中最老的一个任务(即最先进入队列的任务),然后尝试把新提交的任务加入队列。在ThreadPoolExecutor类的rejectedExecution方法中,如果使用DiscardOldestPolicy策略,会先移除队列头部的任务(q.poll()),然后尝试添加新任务(q.offer(r))。
    • 应用场景:适用于希望处理较新任务的场景。比如在一些实时任务调度系统中,新的任务可能比旧任务更具有时效性和重要性,丢弃旧任务可以让系统更专注于处理最新的任务。