SpringBoot 對Future模式的支援

來醉一場發表於2019-01-08

  我們在實際專案中有些複雜運算、耗時操作,就可以利用多執行緒來充分利用CPU,提高系統吞吐量。SpringBoot對多執行緒支援非常好,對我們的開發非常便捷。
  Future模式是多執行緒開發中非常常見的一種設計模式。核心思想是非同步呼叫。當我們執行一個方法時,方法中有多個耗時任務需要同時去做,而且又不著急等待這個結果時可以讓客戶端立即返回然後,後臺慢慢去計算任務。
  當我們做一件事的時候需要等待,那麼我們就可以在這個等待時間內來去做其它事情,這樣就可以充分利用時間。比如我們點外賣,需要一段時間,那麼我們在等外賣的時間裡可以看點書,看個電影。這就是典型的Future模式。如果是普通模式的話,就是等外賣的時候就等外賣,外賣到了後再去看書,極大的浪費時間。
  SpringBoot對Future模式支援非常好,只需要簡單的程式碼就能實現。

1.Future的相關方法

  • boolean cancel(boolean mayInterruptIfRunning); //可以在任務執行過程中取消任務
  • boolean isCancelled(); //判斷Future任務是否取消
  • boolean isDone(); //判斷任務是否完成
  • V get();//獲取任務最終結果,這是一個阻塞方法,會等待任務執行好才會執行後面的程式碼
  • V get(long timeout, TimeUnit unit); //有等待時常的get方法,等待時間到了後仍然沒有計算完成,則拋異常

2.需要的註解

 springboot 配置多執行緒需要兩個註解

  1. @EnableAsync
    在配置類中通過加@EnableAsync開啟對非同步任務的支援
  2. @Async
    在需要執行的方法上加@Async表明該方法是個非同步方法,如果加在類級別上,則表明類所有的方法都是非同步方法

3.配置程式碼

@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {

    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        //核心執行緒數
        taskExecutor.setCorePoolSize(8);
        //最大執行緒數
        taskExecutor.setMaxPoolSize(16);
        //佇列大小
        taskExecutor.setQueueCapacity(100);
        taskExecutor.initialize();
        return taskExecutor;
    }
}
複製程式碼

4.FutureService

@Service
public class FutureService {

    @Async
    public Future<String> futureTest() throws InterruptedException {
        System.out.println("任務執行開始,需要:1000ms");
        for (int i = 0; i < 10; i++) {
            Thread.sleep(100);
            System.out.println("do:" + i);
        }
        System.out.println("完成任務");
        return new AsyncResult<>(Thread.currentThread().getName());
    }
}
複製程式碼

【注】這裡的方法自動被注入使用上文配置的ThreadPoolTaskExecutor

5.測試程式碼

@Resource
private FutureService futureService;

@Test
public void futureTest() throws InterruptedException, ExecutionException {
    long start = System.currentTimeMillis();
    System.out.println("開始");
    //耗時任務
    Future<String> future = futureService.futureTest();
    //另外一個耗時任務
    Thread.sleep(500);
    System.out.println("另外一個耗時任務,需要500ms");

    String s = future.get();
    System.out.println("計算結果輸出:" + s);
    System.out.println("共耗時:" + (System.currentTimeMillis() - start));
}
複製程式碼

6.執行結果

開始
2019-01-07 23:50:34.726  INFO 14648 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService
任務執行開始,需要:1000ms
do:0
do:1
do:2
do:3
另外一個耗時任務,需要500ms
do:4
do:5
do:6
do:7
do:8
do:9
完成任務
計算結果輸出:ThreadPoolTaskExecutor-1
共耗時:1016

Process finished with exit code 0

複製程式碼

本來需要至少1500ms 執行的任務現在只需要1016ms, 因為在執行耗時任務1的同時也在執行耗時任務2,兩個任務並行執行,這就是future模式的好處,在等待時間內去執行其它任務,能夠充分利用時間

【注】本文基於SpringBoot 2.0

GitHub 連線


相關文章