在Java的ThreadPoolExecutor
中,如果线程池的workQueue
已满,并且线程池中的线程数量已经达到maximumPoolSize
,那么新提交的任务将被拒绝。默认情况下,ThreadPoolExecutor
提供了四种预定义的拒绝策略:
AbortPolicy:这是默认的拒绝策略。如果任务被拒绝,它会抛出一个RejectedExecutionException
异常。
CallerRunsPolicy:如果任务被拒绝,它会由调用execute
方法的线程直接执行。
DiscardPolicy:如果任务被拒绝,它会被静默地丢弃,不会有任何通知。
DiscardOldestPolicy:如果任务被拒绝,线程池会丢弃workQueue
中最旧的任务(即最早提交的任务),然后尝试重新执行当前任务。
如果你想要实现自己的丢弃策略,你可以通过实现RejectedExecutionHandler
接口来定义自己的行为。以下是一个简单的自定义丢弃策略的示例,它将丢弃新提交的任务:
javaimport java.util.concurrent.*;
public class DiscardTaskPolicy implements RejectedExecutionHandler {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
// 丢弃新提交的任务
}
}
然后,你可以将这个自定义的拒绝策略传递给ThreadPoolExecutor
的构造函数:
javaimport 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
传递给它。当线程池无法执行新任务时,它将调用handler
的rejectedExecution
方法,而这个方法中没有任何操作,因此新提交的任务将被丢弃。
我们主要来探究一下默认的四种拒绝策略是怎么实现的
分析一下对应的源码
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
是默认的拒绝策略。当任务被拒绝时,它会抛出一个RejectedExecutionException
异常。
javapublic 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
在任务被拒绝时,会由提交任务的线程直接执行该任务。
javapublic 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
在任务被拒绝时,会丢弃workQueue
中最旧的任务(即最早提交的任务),然后尝试重新执行当前任务。
javapublic 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 许可协议。转载请注明出处!