在Java中如何使用ThreadPoolExecutor的饱和策略

来源:站长联盟作者:椎名光头衔:网络博主
导读:本期聚焦于小伙伴创作的《在Java中如何使用ThreadPoolExecutor的饱和策略》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《在Java中如何使用ThreadPoolExecutor的饱和策略》有用,将其分享出去将是对创作者最好的鼓励。

在Java并发编程场景中,ThreadPoolExecutor是官方提供的核心线程池实现类,当我们向线程池提交任务时,如果核心线程都在工作、工作队列已满且线程数达到最大线程数,此时新提交的任务就会触发线程池的饱和策略。饱和策略的作用是定义线程池无法继续处理新任务时的应对规则,避免任务丢失或者系统崩溃。

在Java中如何使用ThreadPoolExecutor的饱和策略

ThreadPoolExecutor的饱和策略类型

ThreadPoolExecutor内置了四种默认的饱和策略,都实现了RejectedExecutionHandler接口,我们可以通过ThreadPoolExecutor的构造方法或者setRejectedExecutionHandler方法来设置对应的策略。

1. AbortPolicy(默认策略)

这是ThreadPoolExecutor的默认饱和策略,当触发饱和时,会直接抛出RejectedExecutionException异常,阻止系统继续提交任务,适合需要明确感知任务提交失败的场景。

import java.util.concurrent.*;

public class AbortPolicyDemo {
    public static void main(String[] args) {
        // 创建线程池:核心线程1,最大线程1,队列容量1,使用默认AbortPolicy
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                1,
                1,
                0L,
                TimeUnit.MILLISECONDS,
                new ArrayBlockingQueue<>(1)
        );
        // 提交3个任务,第3个会触发饱和策略
        for (int i = 0; i < 3; i++) {
            int taskId = i;
            try {
                executor.execute(() -> {
                    System.out.println("执行任务:" + taskId);
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                });
            } catch (RejectedExecutionException e) {
                System.out.println("任务" + taskId + "被拒绝,触发AbortPolicy");
            }
        }
        executor.shutdown();
    }
}

2. CallerRunsPolicy

该策略会将被拒绝的任务交给提交任务的线程来执行,也就是调用execute方法的线程会自己运行这个任务。这种策略可以降低新任务的提交速度,给线程池缓冲时间,适合对任务提交速率有自我调节需求的场景。

import java.util.concurrent.*;

public class CallerRunsPolicyDemo {
    public static void main(String[] args) {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                1,
                1,
                0L,
                TimeUnit.MILLISECONDS,
                new ArrayBlockingQueue<>(1),
                new ThreadPoolExecutor.CallerRunsPolicy()
        );
        for (int i = 0; i < 3; i++) {
            int taskId = i;
            executor.execute(() -> {
                System.out.println("执行任务:" + taskId + ",执行线程:" + Thread.currentThread().getName());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
        executor.shutdown();
    }
}

3. DiscardPolicy

当触发饱和时,该策略会直接丢弃被拒绝的任务,不会抛出任何异常,也不会执行任务。适合那些允许任务丢失、对任务完整性要求不高的场景,比如一些非核心的日志上报任务。

import java.util.concurrent.*;

public class DiscardPolicyDemo {
    public static void main(String[] args) {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                1,
                1,
                0L,
                TimeUnit.MILLISECONDS,
                new ArrayBlockingQueue<>(1),
                new ThreadPoolExecutor.DiscardPolicy()
        );
        for (int i = 0; i < 3; i++) {
            int taskId = i;
            executor.execute(() -> {
                System.out.println("执行任务:" + taskId);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
        executor.shutdown();
    }
}

4. DiscardOldestPolicy

该策略会丢弃队列中等待时间最长的任务,也就是队列头部的任务,然后尝试将新提交的任务加入队列。如果此时队列还是满的,就会继续丢弃,直到能加入为止。适合需要优先处理新任务的场景。

import java.util.concurrent.*;

public class DiscardOldestPolicyDemo {
    public static void main(String[] args) {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                1,
                1,
                0L,
                TimeUnit.MILLISECONDS,
                new ArrayBlockingQueue<>(1),
                new ThreadPoolExecutor.DiscardOldestPolicy()
        );
        for (int i = 0; i < 3; i++) {
            int taskId = i;
            executor.execute(() -> {
                System.out.println("执行任务:" + taskId);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
        executor.shutdown();
    }
}

自定义饱和策略

如果内置的四种饱和策略无法满足业务需求,我们可以自己实现RejectedExecutionHandler接口,自定义饱和策略的逻辑。比如我们需要将被拒绝的任务记录到日志中,同时保存到本地文件后续重试,就可以这样实现:

import java.util.concurrent.*;
import java.io.FileWriter;
import java.io.IOException;

// 自定义饱和策略:记录被拒绝的任务到日志,并保存到文件
class CustomRejectPolicy implements RejectedExecutionHandler {
    @Override
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
        // 记录任务信息
        System.out.println("任务被拒绝,任务信息:" + r.toString());
        // 保存到本地文件
        try (FileWriter writer = new FileWriter("reject_task.log", true)) {
            writer.write("被拒绝的任务:" + r.toString() + "n");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

public class CustomPolicyDemo {
    public static void main(String[] args) {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                1,
                1,
                0L,
                TimeUnit.MILLISECONDS,
                new ArrayBlockingQueue<>(1),
                new CustomRejectPolicy()
        );
        for (int i = 0; i < 3; i++) {
            int taskId = i;
            executor.execute(() -> {
                System.out.println("执行任务:" + taskId);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
        executor.shutdown();
    }
}

饱和策略的选择建议

不同的业务场景需要选择不同的饱和策略,我们可以参考以下建议:

  • 如果任务非常重要,不允许丢失,也不允许系统无感知丢弃,选择AbortPolicy,通过捕获异常来处理失败任务
  • 如果希望提交任务的线程能感知到线程池过载,并且主动降低提交速度,选择CallerRunsPolicy
  • 如果任务属于非核心业务,允许丢失,选择DiscardPolicy
  • 如果新提交的任务比队列中等待的旧任务更重要,选择DiscardOldestPolicy
  • 如果有特殊的任务处理需求,比如持久化、告警等,选择自定义饱和策略

注意事项

在使用饱和策略时,需要注意以下几点:

  • 饱和策略只在核心线程满、队列满、最大线程也满的情况下才会触发,所以合理设置核心线程数、最大线程数和队列容量是避免频繁触发饱和策略的前提
  • 如果使用了CallerRunsPolicy,提交任务的线程会被阻塞直到任务执行完成,可能会影响该线程的其他业务逻辑,需要评估影响范围
  • 自定义饱和策略中不要做太耗时的操作,避免影响线程池的正常调度

ThreadPoolExecutor饱和策略Java线程池RejectedExecutionHandler修改时间:2026-07-12 11:12:30

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。