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


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

一般的我們的做法是串行調用3個函數,把調用返回的結果返回給調用者,這3次調用時串行執行的,如果每個調用耗時1秒的話,3次調用總耗時就是3秒。

這種做法效率非常低,因為3次調用之間無所謂先后順序,所以采用並行執行效率會更好。比如使用線程池ExecutorService實現異步調用。

其實Java8提供了一個非常牛逼的CompletableFuture類,也可以實現異步化:

import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; @Slf4j @Service public class OrderService { /** * 今日訂單數 * * @return */ public CompletableFuture<String> todayOrderCount() { return CompletableFuture.supplyAsync(() -> this.getTodayOrderCount()); } public CompletableFuture<String> todayTurnover() { return CompletableFuture.supplyAsync(() -> this.getTodayTurnover()); } public CompletableFuture<String> totalTurnover() { return CompletableFuture.supplyAsync(() -> this.getTotalTurnover()); } private String getTodayOrderCount() { System.out.println(">>>>>>> 查詢今日訂單數:" + Thread.currentThread().getName()); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } return "50"; } /** * 今日交易額 * * @return */ private String getTodayTurnover() { System.out.println(">>>>>>> 查詢今日交易額:" + Thread.currentThread().getName()); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } return "200"; } /** * 總交易額 * * @return */ private String getTotalTurnover() { System.out.println(">>>>>>> 查詢總交易額:" + Thread.currentThread().getName()); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } return "800"; } } 
import com.alibaba.fastjson.JSONObject; import com.example.sb.service.test.impl.OrderService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.concurrent.CompletableFuture; @Slf4j @RestController @RequestMapping("/order") public class OrderController { @Autowired private OrderService orderService; @GetMapping("/report") public JSONObject report() { long start = System.currentTimeMillis(); JSONObject json = orderReport(); System.out.println("耗時:" + (System.currentTimeMillis() - start)); return json; } private JSONObject orderReport() { CompletableFuture<String> todayOrderCountFuture = orderService.todayOrderCount(); CompletableFuture<String> todayTurnoverFuture = orderService.todayTurnover(); CompletableFuture<String> totalTurnoverFuture = orderService.totalTurnover(); JSONObject json = new JSONObject(); todayOrderCountFuture.whenComplete((v, t) -> { json.put("todayOrderCountFuture", v); }); todayTurnoverFuture.whenComplete((v, t) -> { json.put("todayTurnoverFuture", v); }); totalTurnoverFuture.whenComplete((v, t) -> { json.put("totalTurnoverFuture", v); }); CompletableFuture.allOf(todayOrderCountFuture, todayTurnoverFuture, totalTurnoverFuture) .thenRun(() -> System.out.println("完成!!!!")) .join(); return json; } } 

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

 
 

因為每個OrderService的調用模擬都是耗時1秒,3個調用並行執行,最終耗時自然也是1秒。



作者:不知名的蛋撻
鏈接:https://www.jianshu.com/p/aa7cc1a73c72
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。


免責聲明!

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



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