@Async如何使用

  • 异步的方法上加上@Async异步注解
  • 启动类中需要加上@EnableAsync才有效

    使用时类似于下列函数:
new Thread(()-> System.out.println("hello world !"))

@Async线程池

  • 默认线程池

    无论重复多少次,都默认8个左右的线程在跑

    异步线程:task-1执行成功

    异步线程:task-2执行成功

    异步线程:task-3执行成功

    异步线程:task-4执行成功

    异步线程:task-5执行成功

    异步线程:task-6执行成功

    异步线程:task-7执行成功

    异步线程:task-1执行成功

    异步线程:task-2执行成功

    异步线程:task-8执行成功

    异步线程:task-3执行成功

    异步线程:task-8执行成功

    异步线程:task-6执行成功

    异步线程:task-8执行成功

    异步线程:task-5执行成功

    异步线程:task-3执行成功

    异步线程:task-2执行成功

    异步线程:task-1执行成功
  • 自定义线程池配置
/**
* 为Async配置自定义线程池
* 可存放的最多线程数为:MAX_POOL_SIZE+QUEUE_CAPACITY,同时进入线程池的数量超过这个就会报错
* 线程名称最多为MAX_POOL_SIZE个
*/
@Configuration
public class MyTaskExecutorConfig implements AsyncConfigurer { /**
* 设置ThreadPoolExecutor的核心池大小。
*/
private static final int CORE_POOL_SIZE = 2;
/**
* 设置ThreadPoolExecutor的最大池大小。
*/
private static final int MAX_POOL_SIZE = 3;
/**
* 设置ThreadPoolExecutor的BlockingQueue的容量。
*/
private static final int QUEUE_CAPACITY = 5; /**
* 配置类实现AsyncConfigurer接口并重写getAsyncExcutor方法,并返回一个ThreadPoolTaskExevutor
* 这样我们就获得了一个基于线程池的TaskExecutor
*/
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(CORE_POOL_SIZE);
taskExecutor.setMaxPoolSize(MAX_POOL_SIZE);
taskExecutor.setQueueCapacity(QUEUE_CAPACITY);
taskExecutor.initialize();
return taskExecutor;
}
}

异步线程:ThreadPoolTaskExecutor-2执行成功

异步线程:ThreadPoolTaskExecutor-1执行成功

异步线程:ThreadPoolTaskExecutor-3执行成功

异步线程:ThreadPoolTaskExecutor-1执行成功

异步线程:ThreadPoolTaskExecutor-3执行成功

异步线程:ThreadPoolTaskExecutor-2执行成功

异步线程:ThreadPoolTaskExecutor-1执行成功

异步线程:ThreadPoolTaskExecutor-3执行成功

@Async和@Controller同时使用存在异常

AbstractHandlerMethodMapping初始bean时,在afterPropertiesSet方法中initHandlerMethods()关联我们的SpringMVCBean

// 类型判断
if (beanType != null && isHandler(beanType)) {
// url处理
detectHandlerMethods(beanName);
} // Controller和RequestMapping注解判断
protected boolean isHandler(Class<?> beanType) {
return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}

a、@Controller不使用@Async注解时

@RestController
@Slf4j
public class MemberServiceImpl1 { @GetMapping("/addUser1")
public String addUser() {
log.info(">>>流程1");
log.info(">>>流程2");
return "success";
}
}

b、@Controller使用@Async注解,但不继承接口时,异步失效

@RestController
@Slf4j
public class MemberServiceImpl3 { @GetMapping("/addUser3")
public String addUser() {
log.info(">>>流程1");
addUserLog();
log.info(">>>流程3");
return "success";
} @Async()
public String addUserLog() {
try {
Thread.sleep(1000);
} catch (Exception e) { }
log.info(">>>流程2");
return "success";
}
}



c、@Controller使用@Async注解,同时继承接口

@RestController
@Slf4j
public class MemberServiceImpl4 implements MemberService { @Override
@GetMapping("/addUser4")
public String addUser() {
log.info(">>>流程1");
addUserLog();
log.info(">>>流程3");
return "success";
} @Async()
public String addUserLog() {
try {
Thread.sleep(1000);
} catch (Exception e) { }
log.info(">>>流程2");
return "success";
}
}



@Async使用建议

  • a、异步执行的建议单独开启一个类实现,或者从容器中直接获取到该代理类后执行
/**
* 异步代码写到别的地方,不要和Controller注解同时使用
*/
@RestController
@Slf4j
public class ResolveServiceImpl { @Autowired
private MemberServiceManage memberServiceManage; @GetMapping("/resolve2")
public String addUser() {
log.info(">>>流程1");
memberServiceManage.addUserLog();
log.info(">>>流程3");
return "success";
}
}
@Component
@Slf4j
public class MemberServiceManage {
@Async
public String addUserLog() {
try {
Thread.sleep(1000);
} catch (Exception e) { }
log.info(">>>流程2");
return "success";
}
}
/**
* 使用SpringUtils获得bean后调用,不要使用this操作
*/
@RestController
@Slf4j
public class ResolveServiceImpl { @GetMapping("/resolve1")
public String addUser() {
log.info(">>>流程1");
//把直接调用改为从容器中取一次
ResolveServiceImpl bean = SpringUtils.getBean(ResolveServiceImpl.class);
bean.addUserLog();
log.info(">>>流程3");
return "success";
} @Async()
public String addUserLog() {
try {
Thread.sleep(1000);
} catch (Exception e) { }
log.info(">>>流程2");
return "success";
}
}
  • b、异步的方法上不要加static,加了static就不走AOP了

@Async失效之谜的更多相关文章

  1. springboot2.0 如何异步操作,@Async失效,无法进入异步

    springboot异步操作可以使用@EnableAsync和@Async两个注解,本质就是多线程和动态代理. 一.配置一个线程池 @Configuration @EnableAsync//开启异步 ...

  2. Spring AOP失效之谜

    每天学习一点点 编程PDF电子书免费下载: http://www.shitanlife.com/code 什么是AOP1 AOP(Aspect Oriented Programming),即面向切面编 ...

  3. Spring aop注解失效

    问题 在spring 中使用 @Transactional . @Cacheable 或 自定义 AOP 注解时,对象内部方法中调用该对象的其他使用aop机制的方法会失效. @Transactiona ...

  4. SpringBoot线程池的创建、@Async配置步骤及注意事项

    最近在做订单模块,用户购买服务类产品之后,需要进行预约,预约成功之后分别给商家和用户发送提醒短信.考虑发短信耗时的情况所以我想用异步的方法去执行,于是就在网上看见了Spring的@Async了. 但是 ...

  5. 关于AOP无法切入同类调用方法的问题

    一.前言 Spring AOP在使用过程中需要注意一些问题,也就是平时我们说的陷阱,这些陷阱的出现是由于Spring AOP的实现方式造成的.每一样技术都或多或少有它的局限性,很难称得上完美,只要掌握 ...

  6. Java开发技术

    1.基础技术 数据结构与算法   逻辑结构:数据对象中的数据元素之间的逻辑关系 1.集合结构:集合结构中的数据元素除了同属一个集合外,没有其他关系. 2.线性结构:线性结构中的数据元素之间是一对一的关 ...

  7. 如何在Spring异步调用中传递上下文

    以下文章来源于aoho求索 ,作者aoho 1. 什么是异步调用? 异步调用是相对于同步调用而言的,同步调用是指程序按预定顺序一步步执行,每一步必须等到上一步执行完后才能执行,异步调用则无需等待上一步 ...

  8. 关于Spring注解@Async引发其他注解失效

    概述 在前面一篇文章中,介绍,在一个Bean中注入自己,如果有@Async和@Transaction,如果使用@Autowire注入自身,会报循环依赖,如果使用BeanFactoryAware注入自己 ...

  9. 在同一个类中,一个方法调用另外一个有注解(比如@Async,@Transational)的方法,注解失效的原因和解决方法

    参考原贴地址:https://blog.csdn.net/clementad/article/details/47339519 在同一个类中,一个方法调用另外一个有注解(比如@Async,@Trans ...

随机推荐

  1. Linux下如何使用X86 CPU的GPIO

    目录 1.前言 2.linux pinctrl子系统 3. pin controller driver 4.手动构造device 1.前言 在arm嵌入式开发中,各个外设具有固定的物理地址,我们可以直 ...

  2. Java到处运行的基础之 Class 文件

    Java 实现一次编译到处运行的基础,来源于 Java 虚拟机屏蔽了操作系统的底层细节.使用 class 文件存储编译后的源程序,使得 Java 程序的编译与操作系统解耦.正是因为 Java clas ...

  3. Redis常用命令(5)——Set

    SADD 格式:SADD key member [member ...] 作用:在集合key中插入一个或多个元素.如果member已经存在,则忽略member.如果key不存在则先创建集合key. 返 ...

  4. git同步源码到gitee和github

    如何把我们的源码同步到gitee或github远程仓库中 同步方式分以下几种: 1.命令同步    先查看下我们是否有远程仓库:git remote -v 如有就要删除远程仓库或是同命令覆盖,如全新安 ...

  5. Python使用进程制作爬虫

    详情点我跳转 关注公众号"轻松学编程"了解更多. 1.进程 1.进程的概念 什么是进程->CPU在同一时刻只能处理一个任务,只是因为cpu执行速度很快. cpu在各个任务之间 ...

  6. 构建者模式(Builder pattern)

    构建者模式应用场景: 主要用来构建一些复杂对象,这里的复杂对象比如说:在建造大楼时,需要先打牢地基,搭建框架,然后自下向上地一层一层盖起来.通常,在建造这种复杂结构的物体时,很难一气呵成.我们需要首先 ...

  7. Python 列表的11个重要操作

    列表是python中内置的数据结构,它的表现形式为方括号中不同数据的集合,用逗号分隔开.列表可以用来存储相同数据类型或不同数据类型. 列表是可变的,这也是它如此常用的原因,然而在某些情况下,可变性需要 ...

  8. c#反转

    string[] arr = Console.ReadLine().Split(' '); string result = string.Empty; for (int i = arr.Count() ...

  9. Android基础——项目的文件结构(二)

    Android基础--项目的文件结构(二) AndroidManifest.xml文件分析 [注]此项目文件结构仅限于Android Studio下的Android项目!!! 在一个Android项目 ...

  10. 腾讯云对象存储COS新品发布——智能分层存储,自动优化您的存储成本

    近日,腾讯云正式发布对象存储新品--智能分层存储,能够根据用户数据的访问模式,自动地转换数据的冷热层级,为用户提供与标准存储一致的低延迟和高吞吐的产品体验,同时具有更低的存储成本. 熟悉数据存储的用户 ...