1. 程式人生 > >SpringBoot之——使用@Async實現非同步呼叫

SpringBoot之——使用@Async實現非同步呼叫

一、什麼是“非同步呼叫”

“非同步呼叫”對應的是“同步呼叫”,同步呼叫指程式按照定義順序依次執行,每一行程式都必須等待上一行程式執行完成之後才能執行;非同步呼叫指程式在順序執行時,不等待非同步呼叫的語句返回結果就執行後面的程式。

二、同步呼叫

下面通過一個簡單示例來直觀的理解什麼是同步呼叫:
定義Task類,建立三個處理函式分別模擬三個執行任務的操作,操作消耗時間隨機取(10秒內)

package com.lyz.springboot.task;
import java.util.Random;
import org.springframework.stereotype.Component;
/**
 * 定義3個任務
 * @author liuyazhuang
 */

@Component
publicclass Task1 {
    //定義一個隨機物件.
    public static Random random =new Random();
    //任務一;
    public void doTaskOne() throws Exception {
        System.out.println("開始做任務一");
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        System.out.println("完成任務一,耗時:" + (end - start) + "毫秒");
    }

    //任務二;
    public void doTaskTwo() throws Exception {
        System.out.println("開始做任務二");
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        System.out.println("完成任務二,耗時:" + (end - start) + "毫秒");
    }

    //任務三;
    public void doTaskThree() throws Exception {
        System.out.println("開始做任務三");
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        System.out.println("完成任務三,耗時:" + (end - start) + "毫秒");
    }
}
編寫一個訪問方法:
//測試task1.
@RequestMapping("/task1")
public String task1() throws Exception{
   task1.doTaskOne();
   task1.doTaskTwo();
   task1.doTaskThree();
   return "task1";
}
執行可以看到類似如下輸出:
開始做任務一
完成任務一,耗時:4156毫秒
開始做任務二
完成任務二,耗時:557毫秒
開始做任務三
完成任務三,耗時:6171毫秒

三、非同步呼叫

上述的同步呼叫雖然順利的執行完了三個任務,但是可以看到執行時間比較長,若這三個任務本身之間不存在依賴關係,可以併發執行的話,同步呼叫在執行效率方面就比較差,可以考慮通過非同步呼叫的方式來併發執行。
在Spring Boot中,我們只需要通過使用@Async註解就能簡單的將原來的同步函式變為非同步函式,Task類改在為如下模式:
package com.lyz.springboot.task;

import java.util.Random;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

/**
 * 定義3個任務
 * @author liuyazhuang
 */

@Component
public class Task2 {
    //定義一個隨機物件.
    publicstatic Random random =new Random();
    //任務一;
    @Async
    public void doTaskOne() throws Exception {
        System.out.println("開始做任務一");
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        System.out.println("完成任務一,耗時:" + (end - start) + "毫秒");
    }

 

    //任務二;
    @Async
    public void doTaskTwo() throws Exception {
        System.out.println("開始做任務二");
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        System.out.println("完成任務二,耗時:" + (end - start) + "毫秒");
    }

    //任務3;
    @Async
    public void doTaskThree() throws Exception {
        System.out.println("開始做任務三");
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        System.out.println("完成任務三,耗時:" + (end - start) + "毫秒");
    }
}
為了讓@Async註解能夠生效,還需要在Spring Boot的主程式中配置@EnableAsync,如下所示:
@SpringBootApplication
@EnableAsync
publicclass App {

    //省略其它程式碼…

}
編寫測試方法:
//測試task2.
@RequestMapping("/task2")
public String task2() throws Exception{
   task2.doTaskOne();
   task2.doTaskTwo();
   task2.doTaskThree();
   return"task2";
}
此時可以反覆執行單元測試,您可能會遇到各種不同的結果,比如:
開始做任務一
開始做任務二
開始做任務三
完成任務三,耗時:57毫秒
完成任務二,耗時:3621毫秒
完成任務一,耗時:7419毫秒