[SpringBoot的@Async注解和关键字synchronized的使用]
SpringBoot 的@Async的使用和关键字synchronized的使用
多线程
- SpringBoot 的@Async的使用和关键字synchronized的使用
- 前言
- 一、@Async注解创建异步方法的基础使用?
- 注:简单介绍四种写法
- 第一种是异步删除多个表数据
- 第二种是循环内执行多次此方法
- 第三种是异步执行带返回值
- 第四种是异步执行带返回值等待全部线程执行完再做操作
- 二、使用自己指定的线程池
- 三、关键字synchronized的基本使用
- 总结:仰天大笑出门去,我辈岂是蓬蒿人
前言
在Spring4中,Spring中引入了一个新的注解@Async,这个注解让我们在使用Spring完成异步操作变得非常方便,在SpringBoot环境中,要使用@Async注解,需要先在启动类上加上@EnableAsync注解
一、@Async注解创建异步方法的基础使用?
注:简单介绍四种写法
难度从上到下,其实也不难,就是换种写法
第一种是异步删除多个表数据
没什么好说的
第二种是循环内执行多次此方法
比如循环导入数据,大量数据入库多个表
第三种是异步执行带返回值
主线程需要用到异步方法的返回值,返回值可以是任意的,没有限制
第四种是异步执行带返回值等待全部线程执行完再做操作
主线程等待所有子线程执行完毕,再往下去执行
每种方法都跟着步骤去看
1.首先在启动类配置@EnableAsync**
@SpringBootApplication
// 启用异步
@EnableAsync
public class TestApplication {public static void main(String[] args) {SpringApplication.run(TestApplication.class, args);}}
2.异步方法最好放在一个单独的包下,先创建一个接口类(这里就是一个简单的接口)
public interface AsyncThreadService {/*** @Description: [异步删除保护监测监测数据]* @return: void* @Author: 杨永卓* @Date: 2021/12/24 10:06*/void deleteMonitorDataBh(Map<String, Object> map);/*** @Description: [数据上传与导入异步导入(里程不能为空)]* @Param: [object:假设这是导入的数据]* @return: void* @Author: 杨永卓* @Date: 2022/1/10 13:57*/void addMonitorDataBh(List<Object > object);}
3.编写异步类(需注意类上加@Service,加上此注解类会自动注入到Spring容器中,方法上加@Async注解,表示这是一个异步类)
@Slf4j
@Service
public class AsyncThreadServiceImpl implements AsyncThreadService {/*** @param map* @Description: [异步删除数据,* 当执行这个方法时,这个方法每一行的访问数据库都会单独开启一个线程去执行删除]* @return: void* @Author: 杨永卓* @Date: 2021/12/24 10:06* */@Async@Overridepublic void deleteMonitorDataBh(Map<String, Object> map) {try {log.info("异步数据删除方法开始执行");// 用来删除数据表data1Mapper.deleteByMap(map);log.info("异步删除第1个表数据根据字段");data2Mapper.deleteByMap(map);log.info("异步删除第2个表数据根据字段");data3Mapper.deleteByMap(map);log.info("异步删除第3个表数据根据字段");data4Mapper.deleteByMap(map);log.info("异步删除第4个表数据根据字段");log.info("异步数据删除方法执行完成");} catch (Exception e) {log.error("删除出现问题");e.printStackTrace();//手动回滚数据库操作TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();}}@Async@Overridepublic void addMonitorDataBh(iList<Object > object) {log.info("当前开始导入的数据:{}",object);}@Asyncpublic Future<String> returnString1(Object obj){//假设拿到obj对obj进行处理操作//执行完成返回一个返回值 String str="执行完成";return new AsyncResult(str);}@Asyncpublic Future<String> returnString2(Object obj){//假设拿到obj对obj进行处理操作//执行完成返回一个返回值 String str="执行完成";return new AsyncResult(str);}
}
4.业务层调用测试
@Service
@Slf4j
public class TestServiceImpl implements TestService {//异步@Autowiredprivate AsyncThreadService asyncThreadService;//测试1@Overridepublic boolean deleteData(String sign) throws TppException {Map<String, Object> map = new HashMap<>();map.put("sign", sign);//只有这一行会异步执行asyncThreadService.deleteMonitorDataBh(map);//下面正常写逻辑代码//删除关联文件fileBusinessService.removeByMap(map);return true;}//测试2@Overridepublic void addMonitorDataBh(File file) {// 假设这是一个有10个sheet页的数据流文件,// 并且每个sheet数据量很大,需要异步导入//每一个循环都会启动一个线程去执行这个方法for (int i = 0; i < 10; i++) {//循环拿到了其中一个sheet数据List<Object > objectasyncThreadService.addMonitorDataBh(object);}}//测试3,不等待全部线程执行完进行下面操作@Overridepublic void testReturnStringOne(Object object) {Future<String> task1=asyncThreadService.returnString1(object);Future<String> task2=asyncThreadService.returnString2(object);//get方法是获取返回值的,这里拿到的就是返回的,执行完成这几个字符串task1.get();task2.get();System.out.println(task1.get());System.out.println(task2.get());}//测试4,等待全部线程执行完,再做操作@Overridepublic void testReturnStringOne(Object object) {Future<String> future1=asyncThreadService.returnString1(object);Future<String> future2=asyncThreadService.returnString2(object);//执行while,只有两个异步线程执行完,才会跳出循环,进行下面的操作while (true) {if (future1.isDone() && future2.isDone()){break;}}future1.get();future2.get();System.out.println(future1.get());System.out.println(future2.get());}
}
二、使用自己指定的线程池
也适用上面那种异步写法,多写一种写法更好地提升自己
1、新建一个配置类
@Configuration
@EnableAsync
public class ThreadPoolTaskConfig { /** * 默认情况下,在创建了线程池后,线程池中的线程数为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的名称,默认为首字母小写的方法名 public ThreadPoolTaskExecutor taskExecutor(){ 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.创建两个异步方法类
@Service
public class AsyncService { @Async("taskExecutor") public void sendMessage1() throws InterruptedException { Thread.sleep(5000); // 模拟耗时 } @Async("taskExecutor") public void sendMessage2() throws InterruptedException { Thread.sleep(2000); // 模拟耗时 }
}
3.业务类模拟调用
@Service
public class TaskServic { @Autowired private AsyncServicet asyncService; // 订单处理任务 public void orderTask() throws InterruptedException { this.run(); // 先执行这里面的代码 asyncService.sendMessage1(); // 执行这个方法会睡5秒asyncService.sendMessage2(); // 执行这个方法会睡2秒} // 假设这是一大段业务代码 public void run(){ System.out.println("业务代码1"); System.out.println("业务代码2 "); } }
执行结果:sendMessage2会先执行完,然后才是sendMessage1执行完
三、关键字synchronized的基本使用
使用这个关键字可以保证执行的方法和类在同一时间内只允许一个线程去访问,适用那些
对数据库进行增删改操作的逻辑代码,以免多个线程同事访问出现脏数据,使用也很简单
只需要在方法上添加这个关键字即可。
/*** @Description: [同步方法:修改数据库当前列表数据信息]* @Param: [object:假设是需要操作对应数据库的数据]* @return: void* @Author: 杨永卓* @Date: 2022/1/12 14:10*/private synchronized void updateDataBase(Object object) {//对数据库的操作}
总结:仰天大笑出门去,我辈岂是蓬蒿人
[SpringBoot的@Async注解和关键字synchronized的使用]相关推荐
- SpringBoot利用@Async注解实现异步调用
前言:异步编程是让程序并发运行的一种手段,使用异步编程可以大大提高我们程序的吞吐量,减少用户的等待时间.在Java并发编程中实现异步功能,一般是需要使用线程或者线程池.而实现一个线程,要么继承Thre ...
- 都在建议你不要直接使用 @Async 注解,为什么?
今日推荐 扔掉 Postman,一个工具全部搞定,真香!为啥查询那么慢?还在直接用JWT做鉴权?JJWT真香推荐 15 款常用开发工具干掉 navicat:这款 DB 管理工具才是y(永)y(远)d( ...
- springboot之@Async实现异步
据说springboot有个注解@Async可以实现异步调用,然后我来用用看! 增加一个maven新模块: 增加如下依赖,不增加配置: 然后我们写一个异步调用的服务: 这里需要实现异步的功能,还需要在 ...
- @Async注解的坑,小心
背景 前段时间,一个同事小姐姐跟我说她的项目起不来了,让我帮忙看一下,本着助人为乐的精神,这个忙肯定要去帮. 于是,我在她的控制台发现了如下的异常信息: Exception in thread &qu ...
- @Async注解测试用例附源码(一)
@Async注解测试用例附源码(一) 问题背景 @Async注解测试用例附源码(一) @Async注解异步线程不生效解决方案(二) @Async测试用例 问题总结 测试用例源码下载 Lyric: 我在 ...
- @Async注解其实也就这么回事
前言 我习惯用自定义线程池的方式去做一些异步的逻辑,且这么多年一直都是这样用的. 所以如果是我主导的项目,你在项目里面肯定是看不到 @Async 注解的. 那我之前见过 @Async 注解吗? 肯定是 ...
- SpringBoot使用@Scheduled注解实现定时任务
序言 Spring 3.0 版本之后自带定时任务,提供了@EnableScheduling注解和@Scheduled注解来实现定时任务功能. 使用SpringBoot创建定时任务非常简单,目前主要有以 ...
- springboot中@scheduled注解使用备注
参考文章: https://cloud.tencent.com/developer/article/1497610 https://blog.csdn.net/Rice_kil/article/det ...
- 都在建议,不要直接使用 @Async 注解,为什么?
欢迎关注方志朋的博客,回复"666"获面试宝典 本文讲述@Async注解,在Spring体系中的应用.本文仅说明@Async注解的应用规则,对于原理,调用逻辑,源码分析,暂不介绍. ...
最新文章
- 在ASP.NET中使用WINDOWS模式登录SQL数据库
- sample, batch, epoch 分别是什么?
- 一些非常酷的GAN的应用
- Flask学习记录之Flask-SQLAlchemy
- 华为5G设备全球分布图曝光:欧洲占总量近6成;地平线发布首款车规级AI芯片,名叫征程2.0;奥迪与比亚迪达成电池供货协议……...
- C++ 11 新特性
- 利萨茹(Lissajous)曲线动画演示
- 数据库学习笔记4-隔离级别 Read Committed
- 从知网或PDF复制英文单词间隔过大问题
- Linux之文件通配符
- 谷歌应用内购神器Freedom原理解析
- 截止失真放大电路_【电子干货377】晶体三极管的一些常见应用电路
- oracle rac实现,炼数成金Oracle 12C RAC集群原理与管理实战 16课
- Linux下驱动开发
- “无须”与“无需”最简易区别法
- Redis数据库中Hash哈希的介绍,常用命令和应用场景
- textarea 中的内容自动换行
- C#web弹出提示框的几种方法
- 三篇论文,纵览深度学习在表格识别中的最新应用
- 腾讯开放平台提交app审核无法上传apk文件