天天看點

SpringBoot 異步任務處理

SpringBoot配置異步任務

有些業務是不需要你同步去操作的, 例如: 适用于處理log、發送郵件、短信……等

我們不能因為短信沒發出去而沒有執行接下來的業務邏輯, 這個時候我們就應該去把這些耗時的任務弄成異步的

首先要在啟動類裡面增加如下注解

@EnableAsync

定義異步任務類并使用@Component标記元件被容器掃描,異步方法加上@Async

如果整個類的操作都是異步的話 @Async 可以給類加上, 要把異步任務封裝到類裡面,不能直接寫到Controller

package com.cj.tool.comtool.controller;
 
import com.cj.tool.comtool.task.AsyncTask;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
 
@RestController
public class TestTaskController {
 
    @Autowired
    private AsyncTask asyncTask;
 
 
    // 直接調起異步任務。正常執行肯定是堵塞的
    @GetMapping("/api/v1/test_task")
    public long testTask() throws InterruptedException {
 
        long begin = System.currentTimeMillis();
 
        asyncTask.task1();
        asyncTask.task2();
        asyncTask.task3();
 
        long end = System.currentTimeMillis();
 
        System.out.println("Controller 執行時間" + (end - begin));
 
 
        return end - begin;
    }
 
}
      

  

// 直接調起異步任務。正常執行肯定是堵塞的

package com.cj.tool.comtool.task;
 
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
 
@Component
@Async
public class AsyncTask {
 
    public void task1() throws InterruptedException {
        long begin = System.currentTimeMillis();
        Thread.sleep(1000);
        long end = System.currentTimeMillis();
        System.out.println("task1耗時:"+ (end - begin));
    }
 
    public void task2() throws InterruptedException {
        long begin = System.currentTimeMillis();
        Thread.sleep(2000);
        long end = System.currentTimeMillis();
        System.out.println("task2耗時:"+ (end - begin));
    }
 
    public void task3() throws InterruptedException {
        long begin = System.currentTimeMillis();
        Thread.sleep(3000);
        long end = System.currentTimeMillis();
        System.out.println("task3耗時:"+ (end - begin));
    }
 
 
}
      

可以看到在AsyncTask裡面都是有sleep的, 但是我們使用了異步

SpringBoot 異步任務處理

Controller執行時間 是先輸出的, 我們的任務去開另外的線程執行, 這樣大大增加了我們的程式效率, 在項目裡面合适使用異步任務, 可以大大提高我們的QPS

擷取異步傳回資料

上面例子雖然解決了堵塞的問題, 但是有的時候我們希望擷取異步任務的傳回結果, 再進行後續工作。放心 這個也有方案

添加異步傳回任務

public Future<String> task4() throws InterruptedException {
        long begin = System.currentTimeMillis();
        Thread.sleep(4000);
        long end = System.currentTimeMillis();
        System.out.println("task4耗時:"+ (end - begin));
        return new AsyncResult<>("Task4的資料");
    }
 
    public Future<Integer> task5() throws InterruptedException {
        long begin = System.currentTimeMillis();
        Thread.sleep(5000);
        long end = System.currentTimeMillis();
        System.out.println("task5耗時:"+ (end - begin));
        return new AsyncResult<>(123);
    }
 
    public Future<String> task6() throws InterruptedException {
        long begin = System.currentTimeMillis();
        Thread.sleep(6000);
        long end = System.currentTimeMillis();
        System.out.println("task6耗時:"+ (end - begin));
        return new AsyncResult<>("Task6的資料");
    }      
@GetMapping("/api/v1/test_task")
    public long testTask() throws InterruptedException, ExecutionException {
        long begin = System.currentTimeMillis();
 
//        asyncTask.task1();
//        asyncTask.task2();
//        asyncTask.task3();
 
        Future<String> task4Result = asyncTask.task4();
        Future<Integer> task5Result = asyncTask.task5();
        Future<String> task6Result = asyncTask.task6();
 
        // 等每個任務執行完了就跳出
        for (;;) {
            if (task4Result.isDone() && task5Result.isDone() && task6Result.isDone()) {
                break;
            }
        }
        
        // 擷取傳回結果
        String task4res = task4Result.get();
        int task5res = task5Result.get();
 
        System.out.println(task4res);
        System.out.println(task5res);
 
        long end = System.currentTimeMillis();
 
        System.out.println("Controller 執行時間" + (end - begin));
 
        return end - begin;
    }      

說一下流程

1)增加Future<String> 傳回結果需呀 new AsyncResult<String>("task執行完成");

2)如果需要拿到結果 需要判斷全部的 task.isDone(), 然後再task.get() 擷取傳回資料

效果

可以看到 還是異步的, 最長耗時6000, 這樣就可以應對不同的業務了, 如果是同步的話肯定需要 15000

SpringBoot 異步任務處理

繼續閱讀