关于@Async注解的注意事项

1.在使用@Async的时候,如果异步方法出现异常,调用者无法感知。

@Service
public class AsyncService {

    @Async("asyncServiceExecutorSingle")
    public void asyncTest01(){
        System.out.println("Async Run ...."+Thread.currentThread().getName());
        int i = 1/0;
    }
}

配置类

@Configuration
public class AsyncConfiguration{
    private static final Logger logger = LoggerFactory.getLogger(AsyncException.class);

    @Bean
    public Executor asyncServiceExecutorSingle() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //配置核心线程数
        executor.setCorePoolSize(1);
        //配置最大线程数
        executor.setMaxPoolSize(1);
        //配置队列大小
        executor.setQueueCapacity(1);
        //配置线程池中的线程的名称前缀
        executor.setThreadNamePrefix("async-one-service-");

        // rejection-policy:当pool已经达到max size的时候,如何处理新任务
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //执行初始化
        executor.initialize();
        return executor;
    }
}

测试

@RunWith(SpringRunner.class)
@SpringBootTest
public class AsyncTest {

    @Autowired
    private AsyncService asyncService;

    @Test
    public void test01() {
        try {
            asyncService.asyncTest01();
            //        System.in.read();
            TimeUnit.SECONDS.sleep(3);
        } catch (Exception e) {
            System.out.println(e.getMessage() + "捉住了~");
        }


    }
}

结果
在这里插入图片描述
说明异常并没有被调用者感知,使得处理异常很麻烦。如果异常确实需要我们去手动处理,那么有没有更好的处理办法呢?

通过AsyncConfigurer异常处理 (也可自定义线程池)如下:

修改配置类,实现AsyncConfig接口

@Configuration
public class AsyncConfiguration implements AsyncConfigurer {
    private static final Logger logger = LoggerFactory.getLogger(AsyncConfiguration.class);

    @Bean
    public Executor asyncServiceExecutorSingle() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //配置核心线程数
        executor.setCorePoolSize(1);
        //配置最大线程数
        executor.setMaxPoolSize(1);
        //配置队列大小
        executor.setQueueCapacity(1);
        //配置线程池中的线程的名称前缀
        executor.setThreadNamePrefix("async-one-service-");

        // rejection-policy:当pool已经达到max size的时候,如何处理新任务
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //执行初始化
        executor.initialize();
        return executor;
    }
    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new AsyncExceptionHandler();
    }

    class AsyncExceptionHandler implements  AsyncUncaughtExceptionHandler{

        @Override
        public void handleUncaughtException(Throwable throwable, Method method, Object... objects) {
//            System.out.println(throwable.getMessage()+method.getName());
            logger.error(method.getName(),throwable.getMessage());
        }
    }
}

控制台输出结果

Async Run ....async-one-service-1
2021-06-17 16:25:30.706 ERROR 8708 --- [c-one-service-1] com.halon.AsyncConfiguration             : asyncTest01

2. 调用自己类上的异步方法不起作用

这是官方文档上的第二条注意点
原因:与Spring的生命周期或者说是初始化有关系,如果添加了@Async注解Spring会生成一个代理对象,在执行该方法的时候需要异步执行,就不会调用原本被代理类的该方法。在内部会有一个队列,Spring会把异步方法放入队列里等待线程池去读取去执行方法,从而达到异步的目的。
所以在同一个类中,调用自己类上的异步方法是没有作用的!!!!

类似的:@Transactional注解也是一样的!!!

3.Async拒绝策略以及自定义拒绝策略

大佬博客

4.当有多个@Bean配置且@Async没有指定的时候,默认会使用SimpleAsyncTaskExecutor线程

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值