SpringBoot 異步任務


1.異步和同步

異步(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分鍾。

異步和同步是兩種處理方式,同步適用的場景多,編碼簡單,便於理解,但是在某些特定的場景下異步比同步效率會高出很多。

2.springboot使用異步任務

  1. Application添加注解 @EnableAsync

    @EnableAsync
    @SpringBootApplication
    public class Application {

     public static void main(String[] args) {
         SpringApplication.run(Application.class, args);
     }
    

    }

@EnableAsync 表示支持異步任務,springboot對於異步,定時,緩存,切面等的配置都是通過在啟動類上加 @EnableXXX來配置的。

  1. 異步任務類添加 @Component 注解

表示把任務類當成一個組件注冊,這樣調用時候可以直接注入。

  1. 異步方法添加 @Async 注解

表示該方法會異步執行,也就是說主線程會直接跳過該方法,而是使用線程池中的線程來執行該方法。

@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結束");
    }

}

4)測試類測試

@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class ApplicationTests {

    @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));
    }

}

執行結果

demo地址

github-demo

或者 git clone -b async git@github.com:DannyJoe1994/spring-boot.git


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM