首页 > 其他分享 >@Async详解,为什么生产环境不推荐直接使用@Async?

@Async详解,为什么生产环境不推荐直接使用@Async?

时间:2024-05-26 15:29:17浏览次数:9  
标签:异步 推荐 详解 线程 注解 Async 方法 public

一、@Async 注解介绍:

@Async 注解用于声明一个方法是异步的。当在方法上加上这个注解时,Spring 将会在一个新的线程中执行该方法,而不会阻塞原始线程。这对于需要进行一些异步操作的场景非常有用,比如在后台执行一些耗时的任务而不影响前台响应。

示例:

@Service
public class MyService {
    @Async
    public void asyncMethod() {
        // 异步执行的代码
    }
}

在上面的例子中,asyncMethod 方法使用 @Async 注解标记,表示该方法将在一个独立的线程中执行。

二、@Async 底层分析

1、整体思维导图

2、注解底层实现分析

@Async的实现大概分为以下几个步骤:

  1. // 1、目标代理类

  2. ProxyFactory proxyFactory = new ProxyFactory();

  3. proxyFactory.setTarget("DemoImpl bean");

  4. // 2、代理接口

  5. proxyFactory.addInterface("DemoService");

  6. // 3、设置切点

  7. AsyncAnnotationAdvisor.pointcut = @Async注解

  8. // 4、环绕通知处理

  9. AsyncAnnotationAdvisor.advice = AnnotationAsyncExecutionInterceptor拦截器

  10. // 5、切面 = 切点+通知

  11. proxyFactory.addAdvisor("AsyncAnnotationAdvisor");

  12. // 6、生成代理

  13. UserService userService = proxyFactory.getProxy(getProxyClassLoader());

其中设置切点是在AsyncAnnotationAdvisor类里面

环绕通知处理是在AnnotationAsyncExecutionInterceptor这个拦截器去做的,我们主要就分析一下这个拦截器相关的代码,可以看到直接调用了super(defaultExecutor, exceptionHandler),是在它的父类实现的。

我们看看它的父类

这个类有四个方法:invoke()、getExecutorQualifier()、getDefaultExecutor()、getOrder(),我们主要关注Invoke()方法和getDefaultExecutor()方法。

Invoke()方法如下:

        它的作用就是会找出标注了@Async注解的方法,然后生成一个Callable对象,并提交给线程池的一个线程来执行,从而实现了该方法的异步执行。

  1. 通过AOPUtils.getTargetClass(invocation.getThis()) 获取目标对象的类
  2. 使用 ClassUtils.getMostSpecificMethod() 方法获取指定目标类和方法
  3. 通过 BridgeMethodResolver.findBridgedMethod() 方法处理桥接方法,确保获取到用户声明的方法。(桥接方法用来解决运行时泛型被擦除问题)
  4. determineAsyncExecutor() 方法,根据用户声明的方法确定异步执行器。
  5. 定义一个 Callable 类型的任务,使用 Lambda 表达式创建了一个匿名函数作为任务内容,通过 invocation.proceed() 执行目标方法,并处理可能的异常情况。

  6. this.doSubmit(task, executor, invocation.getMethod().getReturnType()):将任务提交给异步执行器进行处理,并返回执行结果。

getDefaultExecutor()方法如下:

       首先尝试获取 TaskExecutor 实现类的 bean 对象,如果能找到且只有一个,则返回该对象;如果找不到或者找到了多个,则会进入 catch 语句块分支,获取 beanName 为 taskExecutor 的 bean对象,如果获取不到,则会创建一个 SimpleAsyncTaskExecutor 线程池对象。

换句话说,如果直接使用 @Async 注解,Spring 就会直接使用 SimpleAsyncTaskExecutor 线程池。那直接使用 SimpleAsyncTaskExecutor 线程池会出现什么问题呢?现在我们进入第三个主题。

三、@Async 存在的问题或注意事项

1、线程池问题

上面说到,如果直接使用 @Async 注解,Spring 就会直接使用 SimpleAsyncTaskExecutor 线程池。

1)让我们看看这个线程池到底是怎么执行的。

可以看到,它是直接 new 一个线程然后直接开启线程。

他既没有重用线程,也没有设置最大线程数,所以在并发量大的时候会产生严重的性能问题!所以一般在生产环境,特别是 toc 的项目,不建议直接使用 @Async 注解,应该使用自定义线程池搭配 @Async 注解一起使用!

2)那如何配置@Async的自定义线程池呢?

在Spring中,我们可以通过实现 AsyncConfigurer 接口或者直接继承 AsyncConfigurerSupport 类来自定义 Async 异步线程池;

线程池可以直接使用 JDK 提供的 ThreadPoolExecutor 或者 Spring 本身也提供的 TaskExecutor 的实现类,Spring的实现类有以下五种,其中使用最多的就是 ThreadPoolTaskExecutor。

  1. SimpleAsyncTaskExecutor:不是真的线程池,这个类不重用线程,每次调用都会创建一个新的线程。
  2. SyncTaskExecutor:这个类没有实现异步调用,只是一个同步操作。只适用于不需要多线程的地
  3. ConcurrentTaskExecutor:Executor的适配类,不推荐使用。如果ThreadPoolTaskExecutor不满足要求时,才用考虑使用这个类
  4. ThreadPoolTaskScheduler:可以使用cron表达式
  5. ThreadPoolTaskExecutor:最常使用,推荐。其实质是对java.util.concurrent.ThreadPoolExecutor的包装

接下来,我们就以 ThreadPoolTaskExecutor 为例来自定义一个线程池:

2、与 @Transactional 联用问题

        当然,使用@Async还有一些别的注意事项,比如与@Transcational联用时,它们在同一个方法上同时使用时可能导致异步失效。这是因为 @Async 通常会使用一个新的线程,而新线程无法继承原始线程的事务上下文。

        解决办法是将 @Async 注解放在另外的类或者方法上,确保异步方法被另外的代理类包装。这样,异步方法就能够在独立的线程中执行,同时也能够继承事务上下文。

@Service
public class MyService {
    @Async
    public void asyncMethodWithTransaction() {
        transactionalMethod();
    }
    @Transactional
    public void transactionalMethod() {
        // 事务性操作的代码
    }
}

3、循环依赖问题

现在有两个类,ServiceA 和 ServiceB 如下:

@Service
public class ServiceA {

    private final ServiceB serviceB;

    @Autowired
    public ServiceA(ServiceB serviceB) {
        this.serviceB = serviceB;
    }

    @Async
    public void asyncMethod() {
        // 异步方法逻辑
    }
}
@Service
public class ServiceB {

    private final ServiceA serviceA;

    @Autowired
    public ServiceB(ServiceA serviceA) {
        this.serviceA = serviceA;
    }
}

其中serviceA、serviceB对象之间相互依赖,serviceA和serviceB总有一个会先实例化,而serviceA或serviceB里面使用了@Async注解,会导致循环依赖异常:

org.springframework.beans.factory.BeanCurrentlyInCreationException

在springboot中,以上报错被捕捉,抛出的异常是:

The dependencies of some of the beans in the application context form a cycle

原因

        我们知道,spring三级缓存一定程度上解决了循环依赖问题。A对象在实例化之后,属性赋值【opulateBean(beanName, mbd, instanceWrapper)】执行之前,将ObjectFactory添加至三级缓存中,从而使得在B对象实例化后的属性赋值过程中,能从三级缓存拿到ObjectFactory,调用getObject()方法拿到A的引用,B由此能顺利完成初始化并加入到IOC容器。此时A对象完成属性赋值之后,将会执行初始化【initializeBean(beanName, exposedObject, mbd)方法】,重点是@Async注解的处理正是在这地方完成的,其对应的后置处理器AsyncAnnotationBeanPostProcessor,在postProcessAfterInitialization方法中将返回代理对象,此代理对象与B中持有的A对象引用不同,导致了以上报错。

解决办法

  1. 在A类上加@Lazy,保证A对象实例化晚于B对象
  2. 不使用@Async注解,通过自定义异步工具类发起异步线程(线程池)
  3. 不要让@Async的Bean参与循环依赖

@Async循环依赖问题参考博客https://cloud.tencent.com/developer/article/1497689

ps:以下是我整理的java面试资料,感兴趣的可以看看。最后,创作不易,觉得写得不错的可以点点关注!

链接:https://www.yuque.com/u39298356/uu4hxh?# 《Java知识宝典》 

标签:异步,推荐,详解,线程,注解,Async,方法,public
From: https://blog.csdn.net/qq_53281187/article/details/139206916

相关文章

  • word页眉线如何置于文字下方(推荐)
    双击激活页眉敲黑板,点红圈那里会变化如下......
  • TalkingData 数据统计详解
    一、引言在现代数据驱动的商业环境中,准确、及时的数据统计与分析对于企业的决策具有至关重要的作用。TalkingData是中国领先的独立第三方数据智能服务平台,专注于提供专业的数据统计和分析解决方案。本文将详细介绍TalkingData的基本概念、主要功能、使用方法及其在实际......
  • C语言操作符详解
    文章目录一、操作符分类二、二进制和进制转换1、各种进制的区别2、二进制转十进制3、二进制转八进制和十六进制三、原码、反码、补码四、移位操作符1、左移操作符2、右移操作符五、位操作符。1、按位与&2、按位或|3、按位异或^4、按位取反~六、单目操作符1、!非运......
  • 基础6 探索JAVA图形编程桌面:集合组件详解
            我们的团队历经了数不胜数的日夜,全力以赴地进行研发与精心调试,最终成功地推出了一款具有革命性意义的“图形化编程桌面”产品。这款产品的诞生,不仅极为彻底地打破了传统代码开发那长久以来的固有模式,更是把焦点聚集于解决长期以来一直困扰着开发者的一大难题—......
  • 2024年5月大语言模型论文推荐:模型优化、缩放到推理、基准测试和增强性能
    前一篇文章总结了关于计算机视觉方面的论文,这篇文章将要总结了2024年5月发表的一些最重要的大语言模型的论文。这些论文涵盖了塑造下一代语言模型的各种主题,从模型优化和缩放到推理、基准测试和增强性能。大型语言模型(llm)发展迅速,跟上这些领域新颖的研究将有助于引导模型的持续......
  • 基于Kaggle学习MONAI(三)2D-Segmentation例程代码详解1
    1简介         MONAI网站提供了2D分类/分割、3D分类/分割等例程代码如下图所示,通过学习例程代码,初学者能够尽快掌握MONAI框架,但是由于开源框架软件版本更新较快、各模块功能难以协调等原因,这些例程往往无法在Kaggle平台直接运行。本文对MONAI官网第二个例程,即2D分割......
  • 计算机毕业设计项目推荐,82131基于SSM的流浪动物救助网站的设计与实现(开题答辩+程序定
    SSM流浪动物救助网站摘要随着生活水平的持续提高和家庭规模的缩小,宠物已经成为越来越多都市人生活的一部分,随着宠物的增多,流浪的动物的日益增多,中国的流浪动物领养和救助也随之形成规模,同时展现巨大潜力。本次系统的是基于SSM框架的流浪动物救助网站管理系统,平台用户可以......
  • (免费领源码)Java/Mysql数据库+53102互联网美食分享平台,计算机毕业设计项目推荐上万套实
    springboot互联网互联网美食分享平台系   院XXXX学科门类XXX专   业 XXX班级XXX学   号XXX姓   名XXX指导菜谱大全 XXX菜谱大全职称XXX2023年2月摘 要大数据时代下,数据呈爆炸式地增长。为了迎合信息化时代的潮流和信息化......
  • (免费领源码)Java/Mysql数据库+53135高校大学生学科竞赛管理系统,计算机毕业设计项目推荐
    springboot高校大学生学科竞赛管理系统的设计与实现系   院XXXX学科门类XXX专   业 XXX班级XXX学   号XXX姓   名XXX2023年4月摘 要随着互联网趋势的到来,各行各业都在考虑利用互联网将自己推广出去,最好方式就是建立自己的互联......
  • (免费领源码)Java/Mysql数据库+53233基于SpringBoot的社区疫情防控系统,计算机毕业设计项
    springboot社区疫情防控管理系统摘 要信息化社会内需要与之针对性的信息获取途径,但是途径的扩展基本上为人们所努力的方向,由于站在的角度存在偏差,人们经常能够获得不同类型信息,这也是技术最为难以攻克的课题。针对社区疫情防控管理系统等问题,对社区疫情防控管理系统进行研......