网站首页 > java教程 正文
作者:Muscleheng
blog.csdn.net/Muscleheng/article/details/81409672
前言
最近在做订单模块,用户购买服务类产品之后,需要进行预约,预约成功之后分别给商家和用户发送提醒短信。考虑发短信耗时的情况所以我想用异步的方法去执行,于是就在网上看见了Spring的@Async了。
但是遇到了许多问题,使得@Async无效,也一直没有找到很好的文章去详细的说明@Async的正确及错误的使用方法及需要注意的地方,这里简单整理了一下遇见的问题,Sring是以配置文件的形式来开启@Async,而SpringBoot则是以注解的方式开启。
我们可以使用springBoot默认的线程池,不过一般我们会自定义线程池(因为比较灵活),配置方式有:
- 使用 xml 文件配置的方式
- 使用Java代码结合@Configuration进行配置(推荐使用)
下面分别实现两种配置方式
第一步、配置@Async
一、springBoot启动类的配置:
在Spring Boot的主程序中配置@EnableAsync,如下所示:
二、Spring XML的配置方式:
1.applicationContext.xml同目录下创建文件threadPool.xml文件:
2.然后在applicationContext.xml中引入threadPool.xml:<import resource="threadPool.xml" />
第二步:创建两个异步方法的类,如下所示:
第一个类(这里模拟取消订单后发短信,有两个发送短信的方法):
第二个类。调用发短信的方法 (异步方法不能与被调用的异步方法在同一个类中,否则无效):
经过测试得到如下结果:
1.没有使用@Async
2.使用了@Async
可以看出,没有使用@Async方式实现的发送短信是同步执行的,意思就是说第一条发送之后再发送第二条,第二条发送成功之后再给用户提示,这样显然会影响用户体验,再看使用了@Async实现的,在执行第一个发送短信方法之后马上开启另一个线程执行第二个方法,显然这样我们的处理速度回快很多。
使用Java代码结合@Configuration注解的配置方式(推荐使用)
1. 新建一个配置类
package com.boot.common.conf;
import java.util.concurrent.ThreadPoolExecutor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
/**
* 线程池配置
*@authorzhh
*
*/
@Configuration
@EnableAsync
public classThreadPoolTaskConfig{
/**
* 默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个线程去执行任务,
* 当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中;
* 当队列满了,就继续创建线程,当线程数量大于等于maxPoolSize后,开始使用拒绝策略拒绝
*/
/** 核心线程数(默认线程数) */
private static final int corePoolSize = 20;
/** 最大线程数 */
private static final int maxPoolSize = 100;
/** 允许线程空闲时间(单位:默认为秒) */
private static final int keepAliveTime = 10;
/** 缓冲队列大小 */
private static final int queueCapacity = 200;
/** 线程池名前缀 */
private static final String threadNamePrefix = "Async-Service-";
@Bean("taskExecutor") // bean的名称,默认为首字母小写的方法名
publicThreadPoolTaskExecutortaskExecutor(){
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setQueueCapacity(queueCapacity);
executor.setKeepAliveSeconds(keepAliveTime);
executor.setThreadNamePrefix(threadNamePrefix);
// 线程池对拒绝任务的处理策略
// CallerRunsPolicy:由调用线程(提交任务的线程)处理该任务
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 初始化
executor.initialize();
return executor;
}
}
2.创建两个异步方法的类(和之前的类类似仅仅是方法上注解不一样),如下所示:
第一个类(这里模拟取消订单后发短信,有两个发送短信的方法):
代码中的 @Async("taskExecutor") 对应我们自定义线程池中的 @Bean("taskExecutor") ,表示使用我们自定义的线程池。
第二个类。调用发短信的方法 (异步方法不能与被调用的异步方法在同一个类中,否则无效):
运行截图:
注意看,截图中的 [nio-8090-exec-1] 是Tomcat的线程名称
[Async-Service-1]、[Async-Service-2]表示线程1和线程2 ,是我们自定义的线程池里面的线程名称,我们在配置类里面定义的线程池前缀:
private static final String threadNamePrefix = "Async-Service-"; // 线程池名前缀,说明我们自定义的线程池被使用了。
注意事项
如下方式会使@Async失效
- 异步方法使用static修饰
- 异步类没有使用@Component注解(或其他注解)导致spring无法扫描到异步类
- 异步方法不能与被调用的异步方法在同一个类中
- 类中需要使用@Autowired或@Resource等注解自动注入,不能自己手动new对象
- 如果使用SpringBoot框架必须在启动类中增加@EnableAsync注解
- 上一篇: JAVA创建线程的三种方式、创建线程池的四种方式
- 下一篇: Java线程池的正确创建方式
猜你喜欢
- 2024-11-23 不清楚Java线程池实现原理?那你应该收藏这篇文章!「源码分析」
- 2024-11-23 Java基础——Java多线程(线程的创建方式)
- 2024-11-23 「一文搞懂」Java线程池实现原理
- 2024-11-23 Java线程池
- 2024-11-23 java线程池实现原理以及应用场景说明
- 2024-11-23 快速弄懂Java线程池
- 2024-11-23 java线程池原理浅析
- 2024-11-23 彻底了解线程池的原理——40行从零开始自己写线程池
- 2024-11-23 Java并发编程(8):Executor框架 - 可扩展线程池WorkStealingPool
- 2024-11-23 java中的线程池
你 发表评论:
欢迎- 最近发表
-
- 五,网络安全IDA Pro反汇编工具初识及逆向工程解密实战
- 「JAVA8」- Lambda 表达式(java lambda表达式原理)
- 深入探讨Java代码保护:虚拟机保护技术的新时代
- Nginx反向代理原理详解(图文全面总结)
- 逆向拆解日本IT,哪些Java技术栈薪资溢价高
- mybatis 逆向工程使用姿势不对,把表清空了,心里慌的一比
- Spring Boot集成ProGuard轻松实现Java 代码混淆, Java 应用固若金汤
- 从 Java 代码逆向工程生成 UML 类图和序列图
- 人与人相处:尊重是标配,靠谱是高配,厚道是顶配
- Windows系统安装日期如何修改(windows10怎么修改安装日期)
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)