异步调用(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 若标题中有"转载"字样,则本文版权归原作者所有。若无转载字样,本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利.