使用CompletableFuture實現業務服務的異步調用實戰代碼

假如我有一個訂單相關的統計接口,須要返回3樣數據:今日訂單數、今日交易額、總交易額。java

通常的咱們的作法是串行調用3個函數,把調用返回的結果返回給調用者,這3次調用時串行執行的,若是每一個調用耗時1秒的話,3次調用總耗時就是3秒。web

這種作法效率很是低,由於3次調用之間無所謂前後順序,因此採用並行執行效率會更好。好比使用線程池ExecutorService實現異步調用。spring

其實Java8提供了一個很是牛逼的CompletableFuture類,也能夠實現異步化:json

 

 1 import lombok.extern.slf4j.Slf4j;
 2 import org.springframework.stereotype.Service;
 3 
 4 import java.util.concurrent.CompletableFuture;
 5 import java.util.concurrent.TimeUnit;
 6 
 7 @Slf4j
 8 @Service
 9 public class OrderService {
10 
11     /**
12      * 今日訂單數
13      *
14      * @return
15      */
16     public CompletableFuture<String> todayOrderCount() {
17         return CompletableFuture.supplyAsync(() -> this.getTodayOrderCount());
18     }
19 
20     public CompletableFuture<String> todayTurnover() {
21         return CompletableFuture.supplyAsync(() -> this.getTodayTurnover());
22     }
23 
24     public CompletableFuture<String> totalTurnover() {
25         return CompletableFuture.supplyAsync(() -> this.getTotalTurnover());
26     }
27 
28     private String getTodayOrderCount() {
29         System.out.println(">>>>>>> 查詢今日訂單數:" + Thread.currentThread().getName());
30         try {
31             TimeUnit.SECONDS.sleep(1);
32         } catch (InterruptedException e) {
33             e.printStackTrace();
34         }
35         return "50";
36     }
37 
38     /**
39      * 今日交易額
40      *
41      * @return
42      */
43     private String getTodayTurnover() {
44         System.out.println(">>>>>>> 查詢今日交易額:" + Thread.currentThread().getName());
45         try {
46             TimeUnit.SECONDS.sleep(1);
47         } catch (InterruptedException e) {
48             e.printStackTrace();
49         }
50         return "200";
51     }
52 
53     /**
54      * 總交易額
55      *
56      * @return
57      */
58     private String getTotalTurnover() {
59         System.out.println(">>>>>>> 查詢總交易額:" + Thread.currentThread().getName());
60         try {
61             TimeUnit.SECONDS.sleep(1);
62         } catch (InterruptedException e) {
63             e.printStackTrace();
64         }
65         return "800";
66     }
67 }

 

 1 import com.alibaba.fastjson.JSONObject;
 2 import com.example.sb.service.test.impl.OrderService;
 3 import lombok.extern.slf4j.Slf4j;
 4 import org.springframework.beans.factory.annotation.Autowired;
 5 import org.springframework.web.bind.annotation.GetMapping;
 6 import org.springframework.web.bind.annotation.RequestMapping;
 7 import org.springframework.web.bind.annotation.RestController;
 8 
 9 import java.util.concurrent.CompletableFuture;
10 
11 @Slf4j
12 @RestController
13 @RequestMapping("/order")
14 public class OrderController {
15 
16     @Autowired
17     private OrderService orderService;
18 
19     @GetMapping("/report")
20     public JSONObject report() {
21         long start = System.currentTimeMillis();
22         JSONObject json = orderReport();
23         System.out.println("耗時:" + (System.currentTimeMillis() - start));
24         return json;
25     }
26 
27     private JSONObject orderReport() {
28         CompletableFuture<String> todayOrderCountFuture = orderService.todayOrderCount();
29         CompletableFuture<String> todayTurnoverFuture = orderService.todayTurnover();
30         CompletableFuture<String> totalTurnoverFuture = orderService.totalTurnover();
31 
32         JSONObject json = new JSONObject();
33 
34         todayOrderCountFuture.whenComplete((v, t) -> {
35             json.put("todayOrderCountFuture", v);
36         });
37         todayTurnoverFuture.whenComplete((v, t) -> {
38             json.put("todayTurnoverFuture", v);
39         });
40         totalTurnoverFuture.whenComplete((v, t) -> {
41             json.put("totalTurnoverFuture", v);
42         });
43 
44         CompletableFuture.allOf(todayOrderCountFuture, todayTurnoverFuture, totalTurnoverFuture)
45                 .thenRun(() -> System.out.println("完成!!!!"))
46                 .join();
47         return json;
48     }
49 }

 

瀏覽器訪問:http://localhost:8080/order/report 執行結果截圖以下:瀏覽器

 

 

 由於每一個OrderService的調用模擬都是耗時1秒,3個調用並行執行,最終耗時天然也是1秒。app

相關文章
相關標籤/搜索