你的线程池有兜底逻辑吗?Java线程池的拒绝策略有哪些?适用哪些场景?

3 阅读2分钟

Java线程池中的拒绝策略是线程池框架提供的一种机制,用于处理当线程池中的任务队列已满且没有空闲线程可用来执行新任务时的情况。

Java的线程池类ThreadPoolExecutor位于java.util.concurrent 包中,它是一个灵活且广泛使用的线程池实现。线程池通过重用线程来减少线程创建和销毁的开销,提高应用程序的性能,线程池的基本组成如下:

  1. 核心线程数 (corePoolSize) : 核心线程数是线程池在空闲时仍保留的线程数。
  2. 最大线程数 (maximumPoolSize) : 线程池中允许的最大线程数。
  3. 任务队列 (workQueue) : 用于保存等待执行任务的阻塞队列。
  4. 线程工厂 (ThreadFactory) : 用于创建新线程的工厂。
  5. 拒绝策略 (RejectedExecutionHandler) : 当任务无法提交到线程池时,如何处理任务的策略。

拒绝策略的类型

ThreadPoolExecutor 提供了四种内置的拒绝策略:

  1. AbortPolicy: 默认策略。直接抛出 RejectedExecutionException,阻止系统正常工作。
  • 在高可靠性系统中,AbortPolicy 可用于快速发现问题并进行处理。
  • 当任务提交失败后需要立即采取补救措施时。
  1. CallerRunsPolicy: 提交任务的线程自己执行该任务。
  • 适用于不希望丢弃任务且能接受任务执行延迟的场景。
  • 可用于削峰填谷,防止任务过快提交。
  1. DiscardPolicy: 直接丢弃任务,不予任何处理。
  • 适用于不关心单个任务被丢弃的场景。
  • 在负载极高且系统能容忍数据丢失的情况下。
  1. DiscardOldestPolicy: 丢弃队列中最旧的任务,然后尝试重新提交当前任务。
  • 适用于需要保证最新任务的优先级高于旧任务的场景。
  • 在新任务更重要的实时系统中。

自定义拒绝策略

除了内置策略,开发者可以实现 RejectedExecutionHandler 接口来定义自己的拒绝策略,通过这种方式,开发者可以根据具体需求来处理被拒绝的任务。下面是实现自定义策略的步骤:

  1. 实现RejectedExecutionHandler接口。
  2. 覆盖rejectedExecution方法,定义拒绝策略。
  3. ThreadPoolExecutor的构造函数中传入自定义策略。