zoukankan      html  css  js  c++  java
  • spring mvc 异步调用 @Async

    https://blog.csdn.net/qqfo24/article/details/81383022

    spring mvc 异步调用 @Async

    yujunyi_ 2018-08-03 10:35:01 3044 收藏 4
    分类专栏: java
    版权
    定义
    “异步调用”对应的是“同步调用”,同步调用指程序按照定义顺序依次执行,每一行程序都必须等待上一行程序执行完成之后才能执行;异步调用指程序在顺序执行时,不等待异步调用的语句返回结果就执行后面的程序。

    同步调用
    通过一个例子,来看下同步调用。 写了一个 TaskService ,里面有三个方法,分别模拟耗时2秒、3秒、4秒的操作。

    @Service
    public class TaskService {

    public void doTaskOne() throws Exception {
    System.out.println("开始做任务一");
    long start = System.currentTimeMillis();
    Thread.sleep(2000);
    long end = System.currentTimeMillis();
    System.out.println("完成任务一,耗时:" + (end - start) + "毫秒");
    }

    public void doTaskTwo() throws Exception {
    System.out.println("开始做任务二");
    long start = System.currentTimeMillis();
    Thread.sleep(3000);
    long end = System.currentTimeMillis();
    System.out.println("完成任务二,耗时:" + (end - start) + "毫秒");
    }

    public void doTaskThree() throws Exception {
    System.out.println("开始做任务三");
    long start = System.currentTimeMillis();
    Thread.sleep(4000);
    long end = System.currentTimeMillis();
    System.out.println("完成任务三,耗时:" + (end - start) + "毫秒");
    }

    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    写一个 service ,调用这三个方法。

    @Autowired
    private TaskService task;

    public String test() {
    try {
    task.doTaskOne();
    task.doTaskTwo();
    task.doTaskThree();
    }catch (Exception e){
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    下面是运行结果,可以看到三个方法是依次执行的,分别耗时2秒、3秒、4秒、总耗时9秒。

    14:38:13,846 INFO [stdout] (default task-8) 开始做任务一
    14:38:15,848 INFO [stdout] (default task-8) 完成任务一,耗时:2001毫秒
    14:38:15,850 INFO [stdout] (default task-8) 开始做任务二
    14:38:18,850 INFO [stdout] (default task-8) 完成任务二,耗时:3000毫秒
    14:38:18,852 INFO [stdout] (default task-8) 开始做任务三
    14:38:22,853 INFO [stdout] (default task-8) 完成任务三,耗时:4001毫秒
    1
    2
    3
    4
    5
    6
    异步调用
    上面的同步调用,虽然顺利地完成了三个任务,但是执行时间比较长,如果这三个任务没有依赖关系,可以并发执行的话,可以考虑使用异步调用的方法。

    在方法上加上 @Async 注解就能将同步函数变成异步函数,下面是更改后的代码:

    @Service
    public class TaskService {

    @Async
    public void doTaskOne() throws Exception {
    System.out.println("开始做任务一");
    long start = System.currentTimeMillis();
    Thread.sleep(2000);
    long end = System.currentTimeMillis();
    System.out.println("完成任务一,耗时:" + (end - start) + "毫秒");
    }

    @Async
    public void doTaskTwo() throws Exception {
    System.out.println("开始做任务二");
    long start = System.currentTimeMillis();
    Thread.sleep(3000);
    long end = System.currentTimeMillis();
    System.out.println("完成任务二,耗时:" + (end - start) + "毫秒");
    }

    @Async
    public void doTaskThree() throws Exception {
    System.out.println("开始做任务三");
    long start = System.currentTimeMillis();
    Thread.sleep(4000);
    long end = System.currentTimeMillis();
    System.out.println("完成任务三,耗时:" + (end - start) + "毫秒");
    }

    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    另外需要在application.xml中开启异步调用。

    <task:annotation-driven executor="targetExecutor" scheduler="targetScheduler"/>

    <task:executor id="targetExecutor" pool-size="5"/>
    <task:scheduler id="targetScheduler" pool-size="10"/>
    1
    2
    3
    4
    调用方法不用改动,运行后结果如下:

    14:49:16,001 INFO [stdout] (targetExecutor-1) 开始做任务三
    14:49:16,259 INFO [stdout] (targetExecutor-5) 开始做任务二
    14:49:16,260 INFO [stdout] (targetExecutor-4) 开始做任务一
    14:49:18,261 INFO [stdout] (targetExecutor-4) 完成任务一,耗时:2000毫秒
    14:49:19,260 INFO [stdout] (targetExecutor-5) 完成任务二,耗时:3001毫秒
    14:49:20,002 INFO [stdout] (targetExecutor-1) 完成任务三,耗时:4000毫秒
    1
    2
    3
    4
    5
    6
    可以看到3个任务异步执行,总耗时4秒。

    注意
    @Async 所修饰的函数不要定义为 static 类型,这样异步调用不会生效。

    调用方法和异步函数不能在一个 class 中。

    异步回调
    如果想知道异步函数什么时候执行完,那就需要使用 Future 来返回异步调用的结果。

    改造后的代码如下:

    @Service
    public class TaskService {

    @Async
    public Future<String> doTaskOne() throws Exception {
    System.out.println("开始做任务一");
    long start = System.currentTimeMillis();
    Thread.sleep(2000);
    long end = System.currentTimeMillis();
    System.out.println("完成任务一,耗时:" + (end - start) + "毫秒");
    return new AsyncResult<>("任务一完成");
    }

    @Async
    public Future<String> doTaskTwo() throws Exception {
    System.out.println("开始做任务二");
    long start = System.currentTimeMillis();
    Thread.sleep(3000);
    long end = System.currentTimeMillis();
    System.out.println("完成任务二,耗时:" + (end - start) + "毫秒");
    return new AsyncResult<>("任务二完成");
    }

    @Async
    public Future<String> doTaskThree() throws Exception {
    System.out.println("开始做任务三");
    long start = System.currentTimeMillis();
    Thread.sleep(4000);
    long end = System.currentTimeMillis();
    System.out.println("完成任务三,耗时:" + (end - start) + "毫秒");
    return new AsyncResult<>("任务三完成");
    }

    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    调用代码如下,增加了一个计算总耗时的:

    long start = System.currentTimeMillis();

    try {
    Future<String> task1 = task.doTaskOne();
    Future<String> task2 = task.doTaskTwo();
    Future<String> task3 = task.doTaskThree();

    while(true) {
    if(task1.isDone() && task2.isDone() && task3.isDone()) {
    // 三个任务都调用完成,退出循环等待
    break;
    }
    Thread.sleep(100);
    }

    long end = System.currentTimeMillis();
    System.out.println("任务全部完成,总耗时:" + (end - start) + "毫秒");
    }catch (Exception e){
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    运行结果如下:

    15:21:05,676 INFO [stdout] (targetExecutor-4) 开始做任务三
    15:21:05,676 INFO [stdout] (targetExecutor-3) 开始做任务二
    15:21:05,677 INFO [stdout] (targetExecutor-2) 开始做任务一
    15:21:07,678 INFO [stdout] (targetExecutor-2) 完成任务一,耗时:2001毫秒
    15:21:08,677 INFO [stdout] (targetExecutor-3) 完成任务二,耗时:3000毫秒
    15:21:09,677 INFO [stdout] (targetExecutor-4) 完成任务三,耗时:4001毫秒
    15:21:09,704 INFO [stdout] (default task-21) 任务全部完成,总耗时:4036毫秒
    1
    2
    3
    4
    5
    6
    7
    总结
    异步调用可以让一些和主要逻辑无关的代码异步执行,以提升性能。比如一些日志的代码、发送邮件短信等代码,可以使用异步执行。
    ————————————————
    版权声明:本文为CSDN博主「yujunyi_」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/qqfo24/java/article/details/81383022

  • 相关阅读:
    Python网络爬虫 第三章 requests进阶
    Python网络爬虫 第二章 数据解析
    Java 工具库Hutool-db数据库简单操作
    JavaScript基础
    K-Means文档聚类
    利用余弦距离比较文档间的相似度
    算法类——数学问题汇总
    基于K-Means的文本聚类
    加速国内 Github 访问,下载,的9种方案!
    为什么用MQTT而不用TCP长连接透传
  • 原文地址:https://www.cnblogs.com/zhoading/p/13138918.html
Copyright © 2011-2022 走看看