java ---- 统一管理线程池如何捕获异常

介绍

项目中,我们通常需要统一管理线程池,统一管理线程池,有以下几个优点:

  1. 资源控制:创建过多的线程池,会导致系统资源的过多消耗。
  2. 提升性能:创建可以重复使用的线程,可以提高系统性能,因为省去了创建线程、销毁线程的时间。
  3. 自定义功能:通过统一管理线程池,可以自定义系统功能,提升系统性能。
  4. 提升问题定位:通过统一管理线程池,可以控制异常打印,快速定位问题

如何捕获异常

Thread有两个属性,一个实例变量,一个类静态变量
在这里插入图片描述
区别是:实例变量,对当前实例生效;类静态变量对所有线程生效。
一般来说,我们只设置实例变量,我们只希望也只有精力做自己的事没有精力去管其他人的事。
所以,我们自定义异常处理器时,只需要设置实例变量即可。
那么如何捕获线程池中线程的异常呢,由于我们使用的是spring封装的线程池。创建线程的行为已经被封装了,很难自定义,但是通过ThreadPoolTaskExecutor的UML类图,可以看出ThreadPoolTaskExecutor继承了ExecutorConfigurationSupport,而ExecutorConfigurationSupport中将本身设置为了ThreadFactory(因为ExecutorConfigurationSupport实现了ThreadFactory接口,所以可以这样设置),并且ExecutorConfigurationSupport中还提供了一个设置ThreadFactory的方法,可以设置自定义的ThreadFactory,这提供了一个解耦的机会。我们可以自定义ThreadFactory来在创建线程时给线程设置异常处理器。
在这里插入图片描述

代码

引入配置:

@Configuration
@EnableAsync
public class ThreadPoolConfig implements AsyncConfigurer {
    /**
     * 项目共用线程池
     */
    public static final String BADBOYCHAT_EXECUTOR = "badboychatExecutor";

	/**
     * 重写方法以指定当使用注解@Async时使用我们自定义的Executor
     */
    @Override
    public Executor getAsyncExecutor() {
        return badboychatExecutor();
    }

    @Bean(BADBOYCHAT_EXECUTOR)
    @Primary
    public ThreadPoolTaskExecutor badboychatExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(200);
        // 设置优雅停机
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setThreadNamePrefix("badboychat-executor-");
        // 自定义的ThreadFactory,设置了UncaughtExceptionHandler,将异常日志打印出来,方便排查错误
        executor.setThreadFactory(new MyThreadFactory(executor));
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());//满了调用线程执行,认为重要任务
        executor.initialize();
        return executor;
    }
}

MyThreadFactory为自定义的ThreadFactory,重写newThread方法,设置UncaughtExceptionHandler为自定义的异常处理器:

@Slf4j
@AllArgsConstructor
public class MyThreadFactory implements ThreadFactory {

private static final MyUncaughtExceptionHandler MY_UNCAUGHT_EXCEPTION_HANDLER = new MyUncaughtExceptionHandler();

    private ThreadFactory factory;
    @Override
    public Thread newThread(Runnable r) {
        Thread thread = factory.newThread(r);
        thread.setUncaughtExceptionHandler(MY_UNCAUGHT_EXCEPTION_HANDLER);
        return thread;
    }
}

MyUncaughtExceptionHandler为自定义的异常处理器,这个异常处理器是所有实例公用的,所以可以写成单例模式,即

private static final MyUncaughtExceptionHandler MY_UNCAUGHT_EXCEPTION_HANDLER = new MyUncaughtExceptionHandler();

MyUncaughtExceptionHandler代码如下:

@Slf4j
public class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
    @Override
    public void uncaughtException(Thread t, Throwable e) {
        log.error("线程{}发生异常,异常信息为:{}",t.getName(),e.getMessage());
    }
}

这里自定义的异常处理器需要实现Thread的实例变UncaughtExceptionHandler ,原因上面已经说明过。

至此,统一管理线程池时,捕获线程的异常就已经实现了。

  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值