SpringBoot实现异步任务

一.异步和同步

异步(async)是相对于同步(sync)来说的,简单理解,同步是串行的,异步是并行的。

好比说,A需要从B和C两个节点获取数据

第一种方式,A请求B,B返回给A数据,A再去请求C,在从C出获得数据。这种方式就是同步。

另一种方式,A去请求B,不等B返回数据,就去请求C,然后等B和C准备好数据再推送给A,A同样可以拿到B和C的数据,这就是异步。

注意,第二种方式B和C是同时处理A的请求的,是比第一种方式效率要高的,但是这种方式,有一个限制,就是从B和C之间要获取的数据不能有依赖关系,假如获取C的数据时候,C需要从B返回来的数据,那就只能采用第一种方式,先请求B,拿到B的数据,在去请求C。

举个比较直白的例子,把订外卖抽象成几步

  • 1.下单,时间忽略不计。
  • 2.餐厅做饭,10分钟。
  • 3.找外卖小哥,5分钟。(这需要一系列很麻烦的算法算出要通知哪些小哥,等小哥接受派送,再计算出大概到达时间,假设5分钟)
  • 4.派送,5分钟。

按照同步方式处理,1,2,3,4加起来20分钟时间。

但是餐厅做饭和找外卖小哥严格意义上没有依赖关系,2和3是可以同时进行的,这样算,就只需要15分钟。

 异步和同步是两种处理方式,同步适用的场景多,编码简单,便于理解,但是在某些特定的场景下异步比同步效率会高出很多。

二.代码实现,springboot使用异步任务

1.AsyncTaskApplication启动类添加注解 @EnableAsync // 开启异步

2.实现任务类,并注入到spring中

package com.frank;

import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.concurrent.Future;

/**
 * @author 小石潭记
 * @date 2020/6/29 20:52
 * @Description: ${todo}
 */
@Component
public class AsyncTask {

    @Async
    public Future<String> execTaskA() throws InterruptedException {
        System.out.println("TaskA开始");
        long star = new Date().getTime();
        Thread.sleep(5000);
        long end = new Date().getTime();
        System.out.println("TaskA结束,耗时毫秒数:" + (end - star));
        return new AsyncResult<>("TaskA结束");
    }

    @Async
    public Future<String> execTaskB() throws InterruptedException {
        System.out.println("TaskB开始");
        long star = new Date().getTime();
        Thread.sleep(3000);
        long end = new Date().getTime();
        System.out.println("TaskB结束,耗时毫秒数:" + (end - star));
        return new AsyncResult<>("TaskB结束");
    }

    @Async
    public Future<String> execTaskC() throws InterruptedException {
        System.out.println("TaskC开始");
        long star = new Date().getTime();
        Thread.sleep(4000);
        long end = new Date().getTime();
        System.out.println("TaskC结束,耗时毫秒数:" + (end - star));
        return new AsyncResult<>("TaskC结束");
    }
}

3.使用单元测试

package com.frank;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.Date;
import java.util.concurrent.Future;

@SpringBootTest
class AsyncTaskApplicationTests {

    @Autowired
    AsyncTask asyncTask;

    @Test
    public void testAsyncTask() throws InterruptedException {
        long star = new Date().getTime();
        System.out.println("任务开始,当前时间" +star );
        Future<String> taskA = asyncTask.execTaskA();
        Future<String> taskB = asyncTask.execTaskB();
        Future<String> taskC = asyncTask.execTaskC();

        //间隔一秒轮询 直到 A B C 全部完成
        while (true) {
            if (taskA.isDone() && taskB.isDone() && taskC.isDone()) {
                break;
            }
            Thread.sleep(1000);
        }

        long end = new Date().getTime();
        System.out.println("任务结束,当前时间" + end);
        System.out.println("总耗时:"+(end-star));
    }

}

通过异步任务,总耗时6031ms

关闭启动类上的注释,测试,总耗时12003ms

通过对比,异步总耗时更少。

参考文献

猜你喜欢

转载自blog.csdn.net/qq_33371766/article/details/107028400