面试题:Java 线程池有哪些拒绝策略?

在 Java 的 java.util.concurrent 包中,线程池通过 ThreadPoolExecutor 类来管理任务的执行。

当提交的任务超过了线程池的最大容量(即核心线程数加上队列容量)时,就需要一种策略来处理这些无法立即执行的新任务。

这种策略被称为拒绝策略,由 RejectedExecutionHandler 接口定义,并且 ThreadPoolExecutor 提供了几个预定义的实现。

以下是 Java 线程池提供的四种默认拒绝策略:

1. AbortPolicy (默认策略)

  • 行为: 当任务被拒绝时,直接抛出一个 RejectedExecutionException 运行时异常。
  • 适用场景: 当你希望快速失败并明确知道有任务被拒绝的情况时使用。这通常是默认的拒绝策略。
  • 示例代码:
  ThreadPoolExecutor executor = new ThreadPoolExecutor(
      2, 4, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5),
      new ThreadPoolExecutor.AbortPolicy());

2. CallerRunsPolicy

  • 行为: 不抛弃任务也不抛出异常,而是直接在调用 execute 方法的线程中运行该任务。这种方式可以减缓新任务提交的速度,从而给线程池一些喘息的机会。
  • 适用场景: 适合那些需要保证所有任务都被处理但不需要严格遵守响应时间的应用程序。
  • 示例代码:
  ThreadPoolExecutor executor = new ThreadPoolExecutor(
      2, 4, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5),
      new ThreadPoolExecutor.CallerRunsPolicy());

3. DiscardPolicy

  • 行为: 默默地丢弃无法处理的任务而不抛出任何异常。
  • 适用场景: 如果你不关心丢失的任务,并且想要避免因拒绝而产生的额外开销时使用。
  • 示例代码:
  ThreadPoolExecutor executor = new ThreadPoolExecutor(
      2, 4, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5),
      new ThreadPoolExecutor.DiscardPolicy());

4. DiscardOldestPolicy

  • 行为: 抛弃等待队列中最旧的那个未处理任务,然后尝试重新提交当前被拒绝的任务。如果工作队列是优先级队列,则会移除优先级最高的元素。
  • 适用场景: 在某些情况下,比起完全丢弃新任务,更倾向于丢弃最老的任务以腾出空间给新的任务。
  • 示例代码:
  ThreadPoolExecutor executor = new ThreadPoolExecutor(
      2, 4, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5),
      new ThreadPoolExecutor.DiscardOldestPolicy());

自定义拒绝策略

除了上述四种内置的拒绝策略外,还可以通过实现 RejectedExecutionHandler 接口来自定义拒绝策略,以便根据具体需求处理被拒绝的任务。例如,可以记录日志、发送警报或者将任务保存到数据库等。

public class CustomRejectHandler implements RejectedExecutionHandler {
    @Override
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
        // 自定义逻辑,比如记录日志或采取其他措施
        System.out.println("Task rejected");
    }
}

然后在创建 ThreadPoolExecutor 实例时指定这个自定义的拒绝策略:

ThreadPoolExecutor executor = new ThreadPoolExecutor(
    2, 4, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5),
    new CustomRejectHandler());

选择合适的拒绝策略对于确保应用程序的健壮性和可靠性至关重要。理解每种策略的工作原理有助于做出最佳决策。

THE END
喜欢就支持一下吧
点赞5 分享