异步调用(java异步方法怎么写)
异步调用(java异步方法怎么写)
众所周知,java的代码是同步顺序执行,当我们需要执行异步操作时我们需要创建一个新线程去执行,以往我们是这样操作的:/** *任务类 */ classTaskimplementsRunnable{@Override publicvoidrun(){ System.out.println(Thread.currentThread().getName()+":异步任务"); } }//新建线程并执行任务类 newThread(newTask()).start();
jdk1.8之后可以使用Lambda 表达式//新建线程并执行任务类newThread(()->{ System.out.println(Thread.currentThread().getName()+":异步任务"); }).start();
当然,除了显式的new Thread,我们一般通过线程池获取线程,这里就不再展开
Spring 3.0之后提供了一个@Async注解,使用@Async注解进行优雅的异步调用,我们先看一下API对这个注解的定义:https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/scheduling/annotation/Async.html
本文记录在SpringBoot项目中使用@Async注解,实现优雅的异步调用
代码与测试
项目工程结构
因为要测试事务,所以需要引入<!--添加springdata-jpa依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <!--添加MySQL驱动依赖--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency>
在启动类开启启用异步调用,同时注入ApplicationRunner对象在启动类进行调用测试packagecn.huanzi.qch.springbootasync;importcn.huanzi.qch.springbootasync.service.TestService;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.boot.ApplicationRunner;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;importorg.springframework.context.annotation.Bean;importorg.springframework.scheduling.annotation.EnableAsync;importorg.springframework.stereotype.Component;@Component@EnableAsync//开启异步调用@SpringBootApplicationpublicclassSpringbootAsyncApplication{@Autowired privateTestServicetestService;publicstaticvoidmain(String[]args){ SpringApplication.run(SpringbootAsyncApplication.class,args); }/** *启动成功 */ @Bean publicApplicationRunnerapplicationRunner(){returnapplicationArguments->{ longstartTime=System.currentTimeMillis(); System.out.println(Thread.currentThread().getName()+":开始调用异步业务");//无返回值//testService.asyncTask(); //有返回值,但主线程不需要用到返回值//Future<String>future=testService.asyncTask("huanzi-qch"); //有返回值,且主线程需要用到返回值//System.out.println(Thread.currentThread().getName()+":返回值:"+testService.asyncTask("huanzi-qch").get()); //事务测试,事务正常提交//testService.asyncTaskForTransaction(false); //事务测试,模拟异常事务回滚//testService.asyncTaskForTransaction(true); longendTime=System.currentTimeMillis(); System.out.println(Thread.currentThread().getName()+":调用异步业务结束,耗时:"+(endTime-startTime)); }; } }
看一下我们的测试业务类TestServicepackagecn.huanzi.qch.springbootasync.service;importjava.util.concurrent.Future;publicinterfaceTestService{/** *异步调用,无返回值 */ voidasyncTask();/** *异步调用,有返回值 */ Future<String>asyncTask(Strings);/** *异步调用,无返回值,事务测试 */ voidasyncTaskForTransaction(BooleanexFlag); }packagecn.huanzi.qch.springbootasync.service;importcn.huanzi.qch.springbootasync.pojo.TbUser;importcn.huanzi.qch.springbootasync.repository.TbUserRepository;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.scheduling.annotation.Async;importorg.springframework.scheduling.annotation.AsyncResult;importorg.springframework.stereotype.Service;importorg.springframework.transaction.annotation.Transactional;importjava.util.concurrent.Future;@ServicepublicclassTestServiceImplimplementsTestService{@Autowired privateTbUserRepositorytbUserRepository;@Async @Override publicvoidasyncTask(){longstartTime=System.currentTimeMillis();try{//模拟耗时 Thread.sleep(3000); }catch(InterruptedExceptione){ e.printStackTrace(); }longendTime=System.currentTimeMillis(); System.out.println(Thread.currentThread().getName()+":voidasyncTask(),耗时:"+(endTime-startTime)); }@Async("asyncTaskExecutor")@Override publicFuture<String>asyncTask(Strings){longstartTime=System.currentTimeMillis();try{//模拟耗时 Thread.sleep(3000); }catch(InterruptedExceptione){ e.printStackTrace(); }longendTime=System.currentTimeMillis(); System.out.println(Thread.currentThread().getName()+":Future<String>asyncTask(Strings),耗时:"+(endTime-startTime));returnAsyncResult.forValue(s); }@Async("asyncTaskExecutor")@Transactional @Override publicvoidasyncTaskForTransaction(BooleanexFlag){//新增一个用户 TbUsertbUser=newTbUser(); tbUser.setUsername("huanzi-qch"); tbUser.setPassword("123456"); tbUserRepository.save(tbUser);if(exFlag){//模拟异常 thrownewRuntimeException("模拟异常"); } } }
配置线程池packagecn.huanzi.qch.springbootasync.config;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.core.task.AsyncTaskExecutor;importorg.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;/** *线程池的配置 */@ConfigurationpublicclassAsyncConfig{privatestaticfinalintMAX_POOL_SIZE=50;privatestaticfinalintCORE_POOL_SIZE=20;@Bean("asyncTaskExecutor")publicAsyncTaskExecutorasyncTaskExecutor(){ ThreadPoolTaskExecutorasyncTaskExecutor=newThreadPoolTaskExecutor(); asyncTaskExecutor.setMaxPoolSize(MAX_POOL_SIZE); asyncTaskExecutor.setCorePoolSize(CORE_POOL_SIZE); asyncTaskExecutor.setThreadNamePrefix("async-task-thread-pool-"); asyncTaskExecutor.initialize();returnasyncTaskExecutor; } }
配置好后,@Async会默认从线程池获取线程,当然也可以显式的指定@Async("asyncTaskExecutor")
无返回值/** *启动成功 */ @BeanpublicApplicationRunnerapplicationRunner(){returnapplicationArguments->{longstartTime=System.currentTimeMillis(); System.out.println(Thread.currentThread().getName()+":开始调用异步业务");//无返回值 testService.asyncTask();longendTime=System.currentTimeMillis(); System.out.println(Thread.currentThread().getName()+":调用异步业务结束,耗时:"+(endTime-startTime)); }; }
有返回值
有返回值,但主线程不需要用到返回值/** *启动成功 */ @BeanpublicApplicationRunnerapplicationRunner(){returnapplicationArguments->{longstartTime=System.currentTimeMillis(); System.out.println(Thread.currentThread().getName()+":开始调用异步业务");//有返回值,但主线程不需要用到返回值 Future<String>future=testService.asyncTask("huanzi-qch");longendTime=System.currentTimeMillis(); System.out.println(Thread.currentThread().getName()+":调用异步业务结束,耗时:"+(endTime-startTime)); }; }
有返回值,且主线程需要用到返回值/** *启动成功 */ @BeanpublicApplicationRunnerapplicationRunner(){returnapplicationArguments->{longstartTime=System.currentTimeMillis(); System.out.println(Thread.currentThread().getName()+":开始调用异步业务");//有返回值,且主线程需要用到返回值 System.out.println(Thread.currentThread().getName()+":返回值:"+testService.asyncTask("huanzi-qch").get());longendTime=System.currentTimeMillis(); System.out.println(Thread.currentThread().getName()+":调用异步业务结束,耗时:"+(endTime-startTime)); }; }
可以发现,有返回值的情况下,虽然异步业务逻辑是由新线程执行,但如果在主线程操作返回值对象,主线程会等待,还是顺序执行
事务测试
为了方便观察、测试,我们在配置文件中将日志级别设置成debug#修改日志登记,方便调试logging.level.root=debug
事务提交/** *启动成功 */ @BeanpublicApplicationRunnerapplicationRunner(){returnapplicationArguments->{longstartTime=System.currentTimeMillis(); System.out.println(Thread.currentThread().getName()+":开始调用异步业务");//事务测试,事务正常提交 testService.asyncTaskForTransaction(false);longendTime=System.currentTimeMillis(); System.out.println(Thread.currentThread().getName()+":调用异步业务结束,耗时:"+(endTime-startTime)); }; }
模拟异常,事务回滚/** *启动成功 */ @BeanpublicApplicationRunnerapplicationRunner(){returnapplicationArguments->{longstartTime=System.currentTimeMillis(); System.out.println(Thread.currentThread().getName()+":开始调用异步业务");//事务测试,模拟异常事务回滚 testService.asyncTaskForTransaction(true);longendTime=System.currentTimeMillis(); System.out.println(Thread.currentThread().getName()+":调用异步业务结束,耗时:"+(endTime-startTime)); }; }
后记
SpringBoot使用@Async优雅的异步调用就暂时记录到这里,以后再进行补充
代码开源
代码已经开源、托管到我的GitHub、码云:
GitHub:https://github.com/huanzi-qch/springBoot
码云:https://gitee.com/huanzi-qch/springBoot
版权声明
作者:huanzi-qch
出处:
https://www.cnblogs.com/huanzi-qch
若标题中有"转载"字样,则本文版权归原作者所有。若无转载字样,本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利.
神农草本伟哥官方网站全国统一价格?神农草本伟哥多少钱一盒看到,一款风靡朋友圈的产品隆重上市,一种保养品,因此对人体不会造成任何的,帮你远离难言之隐,让你重展,轻而易举。神农草本伟哥到底多少钱一瓶一粒一板神农草本伟哥
特效X5多少钱正品销售效果说明功效订购电话183mdash1088mdash0830(胡经理)威信订购1500mdash1072mdash792(微信优惠)QQ咨询订购200mdash490mdash48((客服小
韩国奇力片多少钱一盒是骗!局?出大事了(解答)韩国奇力片多少钱一盒看到,一款风靡朋友圈的产品隆重上市,一种保养品,因此对人体不会造成任何的,帮你远离难言之隐,让你重展,轻而易举。韩国奇力片到底多少钱一瓶一粒一板韩国奇力片唯一官
韩国奇力片多少钱1盒厂家正品价格韩国奇力片多少钱一盒看到,一款风靡朋友圈的产品隆重上市,一种保养品,因此对人体不会造成任何的,帮你远离难言之隐,让你重展,轻而易举。韩国奇力片到底多少钱一瓶一粒一板韩国奇力片唯一官
韩国奇力片正品价格公布多少钱一盒有几粒订购电话183mdash1088mdash0830(胡经理)威信订购1500mdash1072mdash792(微信优惠)QQ咨询订购200mdash490
黄金玛卡官方网站授权网页美国辉腾黄金玛卡到底多少钱一瓶一粒一板几粒几片几瓶黄金玛卡唯一官方网站电话说明书美国黄金玛卡官网效果规格图片热线订购18310880830()QQ20049048(小徐微信1705
非洲动力源唯一(官方网站)不看不知道!订购电话183mdash1088mdash0830(胡经理)威信订购1500mdash1072mdash792(微信优惠)QQ咨询订购200mdash490
美国顶点3000官方网站厂家指导价!订购电话183mdash1088mdash0830(胡经理)威信订购1500mdash1072mdash792(微信优惠)QQ咨询订购200mdash490mdash48((客服小
中国狸花猫多少钱一只(狸花猫在美国真的很贵么)狸花猫是血统最为纯粹的中华田园猫,也是中国最早记载的猫类之一,宋朝狸猫换太子的典故讲的就是狸花猫的故事。狸花猫生存能力极强,反应灵敏,机警无比,而且是抓老鼠的一把好手。因此,从古至
美短起司猫多少钱一只(美短加白与起司的区别)起司猫不能养的主要原因是因为活动量很大,尤其是晚上,因此需要白天带它出门运动。起司猫的毛发短,但是容易掉毛,更不用说掉毛季,需要每天梳理毛发和打扫卫生。它的好奇心也很重,因此需要保
英短猫多少钱一只(猫咪智商排行榜1100名)英国短毛猫在国内非常受欢迎,它的颜色一共有40多种,但被CFA承认的只有15种。以下是英短猫最常见的几种颜色,你见过几种呢?附上每种颜色的参考价格,不要买贵了NO。1蓝色参考价格8
自考怎么样(自考本科到底靠谱吗)高等教育自学考试是正儿八经国家提倡学信网可查的学历提升形式,本身根苗正红,本来根本跟骗局搭不上边,但为什么你在市面上看到类似的问题还真不少?为什么有人说自考是骗局?其实原因有很多,
营养师考哪些(高级营养师)健康营养师职业的出现,是适应社会健康的需求而产生的。那么想报考健康营养师需要哪些条件?其主要工作内容包括什么?会医学已为考生整理好,如下(此处已添加小程序,请到今日头条客户端查看)
丁香花种植(丁香花怎么养怎么种!)丁香花种植(丁香花怎么养怎么种!)紫丁香又名丁香花,原产于我国华北地区,是我国名贵花卉,象征着淡泊素雅,深受古代文人骚客的喜爱。丁香花生命力顽强,若是将丁香花作为盆栽养殖,相比起养
石榴花图片(石榴树图片大全)石榴花图片(石榴树图片大全)大家好,我是花花。现在这个季节,正是石榴花开的季节,红红的石榴花,不仅开起来特别漂亮,而且还有着非常好的寓意,石榴花代表着富贵,也代表着子孙满堂,很多花
哪个英语软件好(能够学英语的软件)对于想进外企或者从事外贸海外推广相关工作的朋友来说,即使毕业之后也难免遭遇英语这个学生时代的老对手。这里我也推荐几款优秀的学习APP,既能涨知识又能提高英语,都是非常实用的类型。1
英语语法怎么学(零基础英语三个月搞定专升本)语法到底有多重要?请看2020年英语真题题型与分值分布,里面有多少是考察你语法的地方。15道语法选择题4道汉译英翻译题1篇作文,合计57分。这还不算做阅读理解和完形填空所必知的语法
透水砖多少钱一块(30公分x15公分透水砖价格)鉴于透水砖巨大的市场需求,近两年全国掀起了建设透水砖生产线的热潮。据陕煤集团新型环保材料透水砖项目负责人陈云中介绍,去年全国仅有12条透水砖生产线,而今年就已经增长到35条,增长了
理财规划师考试科目(到底什么才是理财规划师?)理财规划师考试科目(到底什么才是理财规划师?)现在可能还有些人存在这样的疑问,理财规划师到底是一些什么样的人?他们的职业工作内容是什么?需要具备什么素质?并且职业发展如何?那么对此
亚马逊网购怎么样(亚马逊靠谱吗买东西)或许你很难想象,可口可乐在中国一度是汽水届的奢侈品。直到改革开放后,由香港发往北京的3000箱瓶装可口可乐,率先打开中国内地外国消费品市场的大门,包括丰田车肯德基在内的更多外资品牌
朝鲜宣布实施大赦近日朝鲜宣布实施大赦登录了热搜,也是在网上引起了网友们的关注,那么很多小伙伴可能还不清楚具体的情况如何,小编也是在网上查阅了一些信息,那么接下来就分享给大家来了解下朝鲜宣布实施大赦
有花堪折直须折(有花堪折直须折,莫待无花空折枝)有花堪折直须折(有花堪折直须折,莫待无花空折枝)有朋友提问请问怎么看这句诗文有花堪折直须折,莫待无花空折枝?如何看待这两句诗,所以跟这诗的作者到底是谁这个最大的争论关系不大,我们也