SpringBoot中异步调用的使用
一.简介
异步调用是相对于同步调用而言的,同步调用是程序在执行时需要一步步执行代码,必须上一步执行完才能够进行下一步,而异步调用则不需要等待上一步执行完就可以继续执行。
二.实现
想实现异步调用,多线程就是实现的一种方式。我们可以实现Runable接口或者继承Thread类,或使用Executors线程池。
在SpringBoot提供了很方便使用异步调用的方式,只需要两个注解就可以实现。
在入口类添加@EnableAsync。
@SpringBootApplication @EnableAsync public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
Controller类。
@RequestMapping("/TestController") @RestController public class TestController { @Autowired private AsyncTask asyncTask; @RequestMapping(value = "/doTask", method = RequestMethod.GET) public String doTask() throws InterruptedException{ long currentTimeMillis = System.currentTimeMillis(); asyncTask.task1(); asyncTask.task2(); asyncTask.task3(); long currentTimeMillis1 = System.currentTimeMillis(); return "task任务总耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms"; } }
异步任务类。注意不能在Controller中直接调用有@Async注解的方法,否则会失效。需要创建一个类来使用@Async方法。异步类需要@Component注解,否则spring会扫描不到。在Controller中使用需要@Autowired注解来进行注入,不能直接new对象。
@Component public class AsyncTask { @Async public void task1() throws InterruptedException{ long currentTimeMillis = System.currentTimeMillis(); Thread.sleep(1000); long currentTimeMillis1 = System.currentTimeMillis(); System.out.println("task1任务耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms"); } @Async public void task2() throws InterruptedException{ long currentTimeMillis = System.currentTimeMillis(); Thread.sleep(2000); long currentTimeMillis1 = System.currentTimeMillis(); System.out.println("task2任务耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms"); } @Async public void task3() throws InterruptedException{ long currentTimeMillis = System.currentTimeMillis(); Thread.sleep(3000); long currentTimeMillis1 = System.currentTimeMillis(); System.out.println("task3任务耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms"); } }
返回结果。
//控制台 task1任务耗时:1000ms task2任务耗时:2001ms task3任务耗时:3000ms //接口返回 task任务总耗时:1ms
如果想知道异步任务什么时候执行完,可以使用Fature回调方式来判断。
@Component public class AsyncTask { @Async public Future<String> task1() throws InterruptedException{ long currentTimeMillis = System.currentTimeMillis(); Thread.sleep(1000); long currentTimeMillis1 = System.currentTimeMillis(); System.out.println("task1任务耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms"); return new AsyncResult<String>("task1执行完毕"); } @Async public Future<String> task2() throws InterruptedException{ long currentTimeMillis = System.currentTimeMillis(); Thread.sleep(2000); long currentTimeMillis1 = System.currentTimeMillis(); System.out.println("task2任务耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms"); return new AsyncResult<String>("task2执行完毕"); } @Async public Future<String> task3() throws InterruptedException{ long currentTimeMillis = System.currentTimeMillis(); Thread.sleep(3000); long currentTimeMillis1 = System.currentTimeMillis(); System.out.println("task3任务耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms"); return new AsyncResult<String>("task3执行完毕"); } } @RequestMapping("/TestController") @RestController public class TestController { @Autowired private AsyncTask asyncTask; @RequestMapping(value = "/doTask", method = RequestMethod.GET) public String doTask() throws InterruptedException{ long currentTimeMillis = System.currentTimeMillis(); Future<String> task1 = asyncTask.task1(); Future<String> task2 = asyncTask.task2(); Future<String> task3 = asyncTask.task3(); String result = null; for (;;) { if(task1.isDone() && task2.isDone() && task3.isDone()) { // 三个任务都调用完成,退出循环等待 break; } Thread.sleep(1000); } long currentTimeMillis1 = System.currentTimeMillis(); result = "task任务总耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms"; return result; } }
返回结果。
//控制台 task1任务耗时:1000ms task2任务耗时:2001ms task3任务耗时:3001ms //接口返回 task任务总耗时:4015ms
三.总结
1.异步调用适合任务较多、耗时较长的情况,比如导入数据。或者和主流程关系不大,可以另开线程执行,比如记录日志。
2.注意在spring boot的启动文件上要添加@EnableAsync注解,要创建异步类来设置@Async注解的异步方法。