有的时候博客内容会有变动,首发博客是最新的,其他博客地址可能会未同步,认准
https://blog.zysicyj.top
可点击链接
https://blog-1253652709.cos.ap-guangzhou.myqcloud.com//picgo/202401180921373.png解答疑问
线程池的拒绝策略
线程池(ThreadPoolExecutor)是Java中用于管理和执行异步任务的一个强大工具。然而,在高并发场景下,线程池中的任务队列可能会被填满,从而导致新的任务无法被提交。这时,线程池就需要处理这些无法处理的任务。线程池的拒绝策略(RejectedExecutionHandler)就是为了解决这个问题而设计的。
1. 线程池的拒绝策略简介
Java的线程池提供了四种内置的拒绝策略,分别是:
- AbortPolicy:直接抛出
RejectedExecutionException,阻止系统正常工作。 - CallerRunsPolicy:由调用线程处理该任务。
- DiscardPolicy:直接丢弃任务,不予任何处理。
- DiscardOldestPolicy:丢弃队列中最旧的未处理任务,然后尝试重新提交被拒绝的任务。
2. 详细源码解析
接下来,我们通过源码深入了解每一种拒绝策略的具体实现。
2.1 AbortPolicy
public static class AbortPolicy implements RejectedExecutionHandler {
public AbortPolicy() { }
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
// 抛出RejectedExecutionException异常
throw new RejectedExecutionException("Task " + r.toString() +
" rejected from " +
e.toString());
}
}
解析:
- AbortPolicy策略会直接抛出 RejectedExecutionException 异常,通知调用者任务被拒绝,并且不会执行该任务。
- 这种策略适合对任务丢失敏感的场景,确保调用者能感知到任务未被执行。
2.2 CallerRunsPolicy
public static class CallerRunsPolicy implements RejectedExecutionHandler {
public CallerRunsPolicy() { }
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
// 由调用线程来运行该任务
r.run();
}
}
}
解析: - CallerRunsPolicy策略不会丢弃任务,而是由提交任务的线程去执行该任务。 - 这种策略可以有效降低向线程池提交任务的速度,适合需要降低任务提交速率的场景。
2.3 DiscardPolicy
public static class DiscardPolicy implements RejectedExecutionHandler {
public DiscardPolicy() { }
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
// 直接丢弃任务,不予处理
}
}
解析: - DiscardPolicy策略在任务被拒绝时直接丢弃该任务,不进行任何处理,也不会抛出异常。 - 这种策略适合不需要确保每个任务都被执行的场景,比如日志记录等。
2.4 DiscardOldestPolicy
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
public DiscardOldestPolicy() { }
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
// 丢弃队列中最旧的任务
e.getQueue().poll();
// 尝试重新提交当前任务
e.execute(r);
}
}
}
解析: - DiscardOldestPolicy策略会丢弃队列中最旧的未处理任务,然后尝试重新提交被拒绝的任务。 - 这种策略适合优先处理最新任务的场景。
3. 自定义拒绝策略
除了以上四种内置策略,开发者还可以实现 RejectedExecutionHandler 接口,定义自己的拒绝策略。以下是一个自定义拒绝策略的示例:
public class CustomRejectPolicy implements RejectedExecutionHandler {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
// 自定义处理逻辑,例如记录日志或持久化任务
System.out.println("Custom reject policy: " + r.toString() + " rejected");
// 可以选择抛出异常或者执行其他操作
throw new RejectedExecutionException("Custom policy: Task " + r.toString() + " rejected from " + e.toString());
}
}
4. 总结
线程池的拒绝策略在高并发场景下尤为重要。根据具体应用场景选择合适的拒绝策略,可以有效地控制系统的稳定性和任务处理效率。了解并掌握这些策略的实现原理,有助于开发者在实际项目中灵活运用。
通过上述内容,我们详细解析了Java线程池的四种内置拒绝策略的源码实现及其适用场景。希望这些内容能帮助你更好地理解和应用线程池的拒绝策略。


