高效率地處理大量數據時,并發調用多個第三方接口能顯著提升效率。然而,簡單的多線程并發可能導致返回結果順序錯亂,與原始數據列表對應不上。本文將介紹如何利用Java的CompletableFuture解決這個問題,確保接口調用結果與原始數據順序完全一致。
問題:
假設需要并發調用1000多個第三方接口并處理返回結果。如果使用簡單的for循環啟動多個線程,接口調用的順序無法保證,最終結果的順序與原始數據列表不符。某些示例代碼使用CompletableFuture.runAsync執行異步任務,但忽略了結果的收集和順序的維護。
解決方案:
為了保證結果順序與原始數據列表一致,關鍵在于使用CompletableFuture.supplyAsync代替CompletableFuture.runAsync。supplyAsync方法可以返回一個結果,而runAsync沒有返回值。通過supplyAsync返回每個接口調用的結果,再利用流式處理將結果收集到列表中,即可確保結果順序與原始數據列表一致。
改進后的代碼:
public static void main(String[] args) { List<String> dataList = new ArrayList<>(); // 原始數據列表 // ... 初始化 dataList ... ExecutorService executorService = new ThreadPoolExecutor( //核心線程數 Runtime.getRuntime().availableProcessors(), //最大線程數 Runtime.getRuntime().availableProcessors() * 2, //線程存活時間 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(), new ThreadPoolExecutor.CallerRunsPolicy()); List<CompletableFuture<String>> futures = new ArrayList<>(); for (String data : dataList) { futures.add(CompletableFuture.supplyAsync(() -> { logger.info("開始執行異步線程->>" + data); // 調用接口,傳入 data // 根據接口返回值判斷 data 是否匹配 // 返回處理后的結果 return processData(data); // 處理數據并返回結果 }, executorService)); // 使用自定義線程池 } // 所有請求完成后處理邏輯 CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).thenRun(() -> { List<String> results = futures.stream() .map(CompletableFuture::join) .collect(Collectors.toList()); logger.info("線程執行完畢:{}", JSON.toJSONString(results)); // 調用發送短信 }).thenRun(() -> executorService.shutdown()); } // 處理數據的方法,根據實際情況修改 private static String processData(String data) { // ... 接口調用和數據處理邏輯 ... return data + "處理后的結果"; }
通過將每個CompletableFuture的結果存儲在futures列表中,并在最后使用futures.stream().map(CompletableFuture::join).collect(Collectors.toList())收集結果,就保證了結果順序與原始數據列表一致。CompletableFuture::join方法會阻塞直到獲取到CompletableFuture的結果。 這樣就有效解決了原代碼中結果順序錯亂的問題。
? 版權聲明
文章版權歸作者所有,未經允許請勿轉載。
THE END