当前位置: 首页 > news >正文

开发中如何自定义线程池

开发中如何自定义线程池

文章目录

  • 开发中如何自定义线程池
    • 1. MyUncaughtExceptionHandler 类
    • 2. MyThreadFactory 类
    • 3. ThreadPoolConfig 类
    • 4.举个案例如何使用
      • 1.异步使用
      • 2.结合 CompletableFuture
        • 2. 异常处理机制说明
        • 3. 验证异常处理效果
        • 4. 更复杂的异常处理链
        • 5.关键区别:CompletableFuture vs 普通异步任务
        • 6.最佳实践建议
        • 7.总结

1. MyUncaughtExceptionHandler 类

这是一个自定义的未捕获异常处理器,当线程因为未捕获异常而终止时,就会调用这个处理器。它会记录错误日志,并且可以添加像通知开发人员等额外的处理逻辑。

package com.hy.archive.config;import lombok.extern.slf4j.Slf4j;/*** Description: 自定义处理器*  这是一个自定义的未捕获异常处理器,当线程因为未捕获异常而终止时,就会调用这个处理器。** @Author Js* @Create 2025-07-08 20:04* @Version 1.0*/
@Slf4j
public class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {@Overridepublic void uncaughtException(Thread t, Throwable e) {log.error("Exception in thread :" + e);// do something//记录日志、告警企业微信钉钉通知开发}
}

使用说明:一般不会直接调用这个类,而是通过线程工厂自动设置到线程上。


2. MyThreadFactory 类

这是一个自定义的线程工厂,其作用是对原生线程工厂进行包装。它会为每个新创建的线程设置一个自定义的未捕获异常处理器,也就是MyUncaughtExceptionHandler

package com.hy.archive.config;import java.util.concurrent.ThreadFactory;/*** Description: 自定义线程工厂处理** @Author Js* @Create 2025-07-08 20:01* @Version 1.0*/
public class MyThreadFactory implements ThreadFactory {private final ThreadFactory original;public MyThreadFactory(ThreadFactory original) {this.original = original;}@Overridepublic Thread newThread(Runnable r) {Thread thread = original.newThread(r);// 异常捕获thread.setUncaughtExceptionHandler(new MyUncaughtExceptionHandler());//自定义的未捕获异常处理器return thread;}
}

使用说明:在配置线程池时,把这个工厂传递给线程池,这样线程池创建的所有线程都会具备异常捕获能力。


3. ThreadPoolConfig 类

这是一个 Spring 配置类,用于创建和配置一个名为accountExecutor的线程池。

package com.hy.archive.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;/*** 自定义单列线程池配置类*/
@Configuration
@EnableAsync
public class ThreadPoolConfig implements AsyncConfigurer {//自定义线程池名称public static final String ACCOUNT_EXECUTOR = "accountExecutor";@Overridepublic Executor getAsyncExecutor() {return accountExecutor();}@Bean(ACCOUNT_EXECUTOR)@Primarypublic ThreadPoolTaskExecutor accountExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(10);executor.setMaxPoolSize(20);executor.setQueueCapacity(500);// 线程池优雅停机的关键executor.setWaitForTasksToCompleteOnShutdown(true);// 线程池前缀配置executor.setThreadNamePrefix("account-exec-");//满了调用线程执行,认为重要任务executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());//设置线程池的异常处理逻辑使用了装饰器设计模式executor.setThreadFactory(new MyThreadFactory(executor));executor.initialize();return executor;}
}

4.举个案例如何使用

1.异步使用

假设你有一个异步服务,使用该线程池执行任务:

@Service
public class MyAsyncService {@Async("accountExecutor") // 指定使用自定义线程池public CompletableFuture<String> processAccount(String accountId) {// 模拟业务逻辑if (accountId == null) {throw new RuntimeException("账户ID不能为空"); // 未捕获异常}// 正常业务逻辑...return CompletableFuture.completedFuture("处理完成");}
}

当调用 processAccount(null) 时,会触发未捕获异常,此时异常处理流程如下:

  1. 线程池中的线程执行任务时抛出 RuntimeException
  2. 由于线程已通过 MyThreadFactory 设置了 MyUncaughtExceptionHandler,异常会被该处理器捕获。
  3. MyUncaughtExceptionHandler 记录错误日志(例如:Exception in thread account-exec-1: 账户ID不能为空)。
  4. 可扩展逻辑(如发送告警)被触发。

2.结合 CompletableFuture

@Service
public class AccountService {@Autowiredprivate ThreadPoolTaskExecutor accountExecutor; // 注入你的线程池public CompletableFuture<String> processAccount(String accountId) {return CompletableFuture.supplyAsync(() -> {// 模拟业务逻辑,可能抛出异常if (accountId == null) {throw new RuntimeException("账户ID不能为空");}// 正常处理逻辑...return "账户处理成功: " + accountId;}, accountExecutor) // 指定使用你的线程池.exceptionally(ex -> {// 处理异常的逻辑log.error("处理账户时发生异常: {}", ex.getMessage(), ex);return "处理失败: " + ex.getMessage(); // 返回默认值或错误信息});}
}
2. 异常处理机制说明
  • supplyAsync + 指定线程池
    使用 accountExecutor 线程池执行异步任务,该线程池已通过你的 MyThreadFactory 设置了 MyUncaughtExceptionHandler
  • exceptionally 回调
    当任务抛出异常时,exceptionally 会捕获异常并返回默认值或处理结果。这是 CompletableFuture 提供的显式异常处理方式。
  • 双重保障
    • 若未使用 exceptionally,异常会被你的 MyUncaughtExceptionHandler 捕获(记录日志并触发告警)。
    • 若使用 exceptionally,异常会被显式处理,同时 MyUncaughtExceptionHandler 仍会记录日志(双重保障)。
3. 验证异常处理效果
@SpringBootTest
class AccountServiceTest {@Autowiredprivate AccountService accountService;@Testvoid testExceptionHandling() throws Exception {// 模拟异常情况CompletableFuture<String> future = accountService.processAccount(null);// 验证异常处理结果String result = future.get(); // 不会抛出异常,因为exceptionally已处理assertEquals("处理失败: 账户ID不能为空", result);// 检查日志:MyUncaughtExceptionHandler也会记录该异常// ERROR Exception in thread account-exec-1: 账户ID不能为空}
}
4. 更复杂的异常处理链

CompletableFuture 提供了多种异常处理方法,可根据需求组合使用:

public CompletableFuture<String> processAccount(String accountId) {return CompletableFuture.supplyAsync(() -> {if (accountId == null) {throw new IllegalArgumentException("账户ID不能为空");}if (!isValid(accountId)) {throw new RuntimeException("账户ID无效");}return "账户处理成功: " + accountId;}, accountExecutor).exceptionally(ex -> {if (ex instanceof IllegalArgumentException) {return "非法参数: " + ex.getMessage();} else {return "系统错误: " + ex.getMessage();}}).thenApply(result -> {// 继续处理结果return "最终结果: " + result;}).exceptionally(ex -> {// 处理后续步骤可能出现的异常return "处理失败: " + ex.getMessage();});
}
5.关键区别:CompletableFuture vs 普通异步任务
场景异常处理方式是否需要 MyUncaughtExceptionHandler
普通异步任务 (@Async)依赖 MyUncaughtExceptionHandler 统一处理必须配置
CompletableFuture + exceptionally显式捕获并处理异常可选(用于日志记录和额外监控)
CompletableFuture + 未处理异常依赖 MyUncaughtExceptionHandler 捕获必须配置
6.最佳实践建议
  1. 优先使用 CompletableFuture 的显式处理
    在异步任务中,尽量通过 exceptionally()handle()whenComplete() 显式处理异常,使代码更健壮。

  2. 保留统一异常处理器作为兜底
    你的 MyUncaughtExceptionHandler 仍有价值,可用于记录所有未被显式处理的异常,避免遗漏问题。

  3. 区分可恢复异常和不可恢复异常
    对不同类型的异常采取不同处理策略,例如:

    .exceptionally(ex -> {if (ex instanceof RetryableException) {// 重试逻辑return retry(accountId);} else {// 记录致命错误并返回默认值log.error("致命错误", ex);return "默认结果";}
    })
    
7.总结

通过结合你的线程池配置和 CompletableFuture 的异常处理机制,你可以实现:

  • 显式异常处理:通过 exceptionally 等方法直接处理已知异常。
  • 统一日志记录:利用 MyUncaughtExceptionHandler 记录所有异常,确保无遗漏。
  • 灵活的错误恢复:根据异常类型执行不同的恢复逻辑。

这种组合方式既保证了代码的健壮性,又便于问题追踪和系统监控。


http://www.lryc.cn/news/582588.html

相关文章:

  • [1-01-01].第50节:泛型 - 泛型的使用
  • 深入了解linux系统—— System V之消息队列和信号量
  • 自动驾驶的“安全基石”:NVIDIA如何用技术守护未来出行
  • 冷链物流配送中心选址与路径优化模型研究
  • 跨越十年的C++演进:C++23新特性全解析
  • 3423. 循环数组中相邻元素的最大差值 — day97
  • 【PTA数据结构 | C语言版】在顺序表 list 的第 i 个位置上插入元素 x
  • JVM 基础 - 类字节码详解
  • Spring自动装配(xml)
  • Vue、Laravel 项目初始化命令对比 / curl 命令/ CORS 机制总结与案例
  • AlphaEvolve:谷歌的算法进化引擎 | 从数学证明到芯片设计的AI自主发现新纪元
  • UI前端大数据处理挑战与对策:大数据量下的实时数据分析技术
  • CD46.【C++ Dev】list的模拟实现(1)
  • 人体坐姿检测系统开发实战(YOLOv8+PyTorch+可视化)
  • WHIP(WebRTC HTTP Ingestion Protocol)详解
  • 装修水电改造需要注意什么?水电改造有哪些注意事项?
  • 力扣-287.寻找重复数
  • 容器技术入门与Docker环境部署
  • 【佳易王娱乐场儿童乐园会员多项目管理系统软件】从 “手工记账” 到 “智能管理”:儿童乐园会员系统的转型价值
  • Docker实用命令
  • 脚本检测 自启 关闭 重启等 tomcat 可修改成其他程序 结合crontab 每天凌晨1点执行
  • LocalStorage和SessionStorage的区别和应用
  • UI前端与数字孪生结合实践案例:智慧零售的库存管理优化系统
  • 车载HMI革命:从物理按键到智能表面的交互逻辑重构
  • 高版本的MacOS如何降级?
  • 250708-Debian系统安装Edge浏览器并配置最小中文输入法
  • KTM5910,24bit 绝对角度磁性编码器,在轴应用,- 内部集成超高性能双 16bit 2M SAR ADC
  • VMware克隆虚拟机,模板机已提前设置了固定IP,克隆机需要修改的事项
  • ECS由浅入深第三节:进阶?System 的行为与复杂交互模式
  • 【openGLES】安卓端EGL的使用