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注解的异步方法。

原文地址:https://www.cnblogs.com/shadoll/p/14431557.html