编辑
2024-05-07
Java
00
请注意,本文编写于 368 天前,最后修改于 368 天前,其中某些信息可能已经过时。

目录

DiscardPolicy
AbortPolicy
CallerRunsPolicy
DiscardOldestPolicy

在Java的ThreadPoolExecutor中,如果线程池的workQueue已满,并且线程池中的线程数量已经达到maximumPoolSize,那么新提交的任务将被拒绝。默认情况下,ThreadPoolExecutor提供了四种预定义的拒绝策略:

  1. AbortPolicy:这是默认的拒绝策略。如果任务被拒绝,它会抛出一个RejectedExecutionException异常。

  2. CallerRunsPolicy:如果任务被拒绝,它会由调用execute方法的线程直接执行。

  3. DiscardPolicy:如果任务被拒绝,它会被静默地丢弃,不会有任何通知。

  4. DiscardOldestPolicy:如果任务被拒绝,线程池会丢弃workQueue中最旧的任务(即最早提交的任务),然后尝试重新执行当前任务。

如果你想要实现自己的丢弃策略,你可以通过实现RejectedExecutionHandler接口来定义自己的行为。以下是一个简单的自定义丢弃策略的示例,它将丢弃新提交的任务:

java
import java.util.concurrent.*; public class DiscardTaskPolicy implements RejectedExecutionHandler { @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { // 丢弃新提交的任务 } }

然后,你可以将这个自定义的拒绝策略传递给ThreadPoolExecutor的构造函数:

java
import java.util.concurrent.*; public class Main { public static void main(String[] args) { // 创建自定义的丢弃策略实例 RejectedExecutionHandler handler = new DiscardTaskPolicy(); // 创建线程池,指定自定义的丢弃策略 ThreadPoolExecutor executor = new ThreadPoolExecutor( 1, // corePoolSize 2, // maximumPoolSize 10, // keepAliveTime TimeUnit.SECONDS, new ArrayBlockingQueue<>(1), // workQueue Executors.defaultThreadFactory(), // threadFactory handler // 指定自定义的丢弃策略 ); // 提交任务到线程池 executor.execute(() -> { System.out.println("Task is running"); }); // 关闭线程池 executor.shutdown(); } }

在这个例子中,我们创建了一个ThreadPoolExecutor实例,并将自定义的丢弃策略handler传递给它。当线程池无法执行新任务时,它将调用handlerrejectedExecution方法,而这个方法中没有任何操作,因此新提交的任务将被丢弃。

我们主要来探究一下默认的四种拒绝策略是怎么实现的

分析一下对应的源码

DiscardPolicy

java
/** * A handler for tasks that cannot be executed by a {@code ThreadPoolExecutor}. */ public static class DiscardPolicy implements RejectedExecutionHandler { /** * Creates a {@code DiscardPolicy}. */ public DiscardPolicy() { } /** * Does nothing, which has the effect of discarding task r. * @param r the runnable task requested to be executed * @param e the executor attempting to execute this task */ public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { } }

rejectedExecution方法中,DiscardPolicy没有执行任何操作,因此当任务被拒绝时,它不会被添加到队列中,也不会被其他线程执行。这个方法的实现非常简单,只是空方法体。

AbortPolicy

AbortPolicy是默认的拒绝策略。当任务被拒绝时,它会抛出一个RejectedExecutionException异常。

java
public static class AbortPolicy implements RejectedExecutionHandler { /** * Creates an {@code AbortPolicy}. */ public AbortPolicy() { } /** * Always throws RejectedExecutionException. * * @param r the runnable task requested to be executed * @param e the executor attempting to execute this task * @throws RejectedExecutionException always */ public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { throw new RejectedExecutionException("Task " + r.toString() + " rejected from " + e.toString()); } }

rejectedExecution方法中,AbortPolicy直接抛出了一个RejectedExecutionException异常,这个异常会被提交任务的线程捕获,通常会导致应用程序的执行流程中断。

CallerRunsPolicy

CallerRunsPolicy在任务被拒绝时,会由提交任务的线程直接执行该任务。

java
public static class CallerRunsPolicy implements RejectedExecutionHandler { /** * Creates a {@code CallerRunsPolicy}. */ public CallerRunsPolicy() { } /** * Executes task r in the caller's thread, unless the executor * has been shut down, in which case the task is discarded. * * @param r the runnable task requested to be executed * @param e the executor attempting to execute this task */ public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) { r.run(); } } }

rejectedExecution方法中,如果线程池没有被关闭,CallerRunsPolicy会调用任务的run方法,这样任务就会在调用execute方法的线程中执行。

DiscardOldestPolicy

DiscardOldestPolicy在任务被拒绝时,会丢弃workQueue中最旧的任务(即最早提交的任务),然后尝试重新执行当前任务。

java
public static class DiscardOldestPolicy implements RejectedExecutionHandler { /** * Creates a {@code DiscardOldestPolicy} for the given executor. */ public DiscardOldestPolicy() { } /** * Obtains and ignores the next task that the executor * would otherwise execute, if one is immediately available, * and then retries execution of task r, unless the executor * is shut down, in which case task r is instead discarded. * * @param r the runnable task requested to be executed * @param e the executor attempting to execute this task */ public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) { e.getQueue().poll(); e.execute(r); } } }

rejectedExecution方法中,DiscardOldestPolicy首先尝试从workQueue中移除最旧的任务,然后重新执行当前任务。如果workQueue为空或者线程池被关闭,当前任务将被丢弃。

本文作者:yowayimono

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!