簡體   English   中英

獲取 CompletableFutures 的 Future 方法

[英]get method on Future of CompletableFutures

我在 java 中做一些多線程工作,我對 Future get方法有疑問。

我有一個提交 n Callable 的ExecutorSevice 提交返回一個Future ,它被添加到一個列表中(稍后在一些代碼中)。 Callable 的call方法遍歷一個列表,並且對於列表中的每一項, someMethod都會被調用並返回一個CompletableFuture<T> 然后,Completable future 被添加到 map。

在循環call結束時返回包含一堆 CompletableFuture 的 map。

因此,初始列表 ( uglyList ) 包含<String, CompletableFuture<String>>的 n 個映射。

我的問題是,當我在uglyList列表的元素上調用get時,執行被阻止,直到訪問整個列表(作為參數傳遞給 Callable)並且所有CompletableFutures都已插入 map 中,對嗎?

因為,我有一個疑問,這個例子中的get是否有可能也等待 map 中的CompletableFutures完成? 我不知道如何測試這個


public class A {

    private class CallableC implements Callable<Map<String, CompletableFuture<String>>> {
        private List<String> listString;

        Map<String, CompletableFuture<String>> futureMap;

        public CallableC(List<String> listString) throws Exception {        
            this.listString = listString;
            this.futureMap = new HashMap<>();
        }

        @Override
        public Map<String, CompletableFuture<String>> call() throws Exception {

            for (int j = 0; j < listString.size(); ++j) {
                CompletableFuture<String> future = someMethod();        
                futureMap.put(listString.get(i), future);
            }

            return futureMap;
        }
    }


    public void multiThreadMethod(List<String> items) throws Exception {

        List<Future<Map<String, CompletableFuture<String>>>> uglyList = new ArrayList<>();

        int coresNumber = (Runtime.getRuntime().availableProcessors());

                // This method split a List in n subList
        List<List<String>> splittedList = split(items, coresNumber);

        ExecutorService executor = Executors.newFixedThreadPool(coresNumber);

        try {

            for (int i = 0; i < coresNumber; ++i) {
                threads.add(executor.submit(new CallableC(splittedList.get(i),)));
            }

            for (int i = 0; i < coresNumber; ++i) {
                uglyList.get(i).get(); //here
            }


        } catch (Exception e) {
                     // YAY errors
        }
        finally {
            executor.shutdown();
        }
    }
}

當我在丑陋列表的一個元素上調用 get 時,執行被阻止,直到訪問整個列表(作為參數傳遞給 Callable)並且所有 CompletableFutures 都已插入 map,對嗎?

對,那是正確的。 get()將等待Callable的完成,在您的情況下,這意味着CallableC#call()方法的結束,該方法將在 for 循環結束時到達,此時CompletableFutures全部創建並插入futureMap ,無論這些CompletableFuture的狀態/完成情況如何。

有可能這個例子中的 get 還等待 map 中的 CompletableFutures 完成?

有可能實現這一點,但並非沒有附加代碼。

在您的代碼中執行此操作的最小方法是在任務內的CompletableFuture上添加一個加入調用。

@Override
    public Map<String, CompletableFuture<String>> call() throws Exception {

        for (int j = 0; j < listString.size(); ++j) {
            CompletableFuture<String> future = someMethod();        
            futureMap.put(listString.get(j), future);
        }
        // This will wait for all the futures inside the map to terminate
        try {
            CompletableFuture.allOf(futureMap.values().toArray(new CompletableFuture[0])).join();
        } catch (CompletionException e) {
            // ignored - the status will be checked later on
        }

        return futureMap;
    }

另一種方法是在最后等待(為簡潔起見,我跳過異常處理):

for (int i = 0; i < coresNumber; ++i) {
    threads.add(executor.submit(new CallableC(splittedList.get(i),)));
}
// This will wait for all the futures to terminate (thanks to f.get())
// And then, all the completable futures will be added to an array of futures that will also be waited upon
CompletableFuture.allOf(
    uglyList.stream().flatMap(f -> f.get().values().stream()).toArray(CompletableFuture[]::new)
).join();

但是,如果可能的話,我會通過僅使用可完成的期貨來簡化整個代碼,除非您有充分的理由以您的方式中斷任務(使用列表列表、專用執行程序等)。 這可能看起來像這樣(可能有一些拼寫錯誤)

List<String> items = ...
ConcurrentMap<String, String> resultsByItem = new ConcurrentHashMap<>();

Future<Void> allWork = CompletableFuture.allOf(
    items.stream()
        .map(item -> someWork(item) // Get a completable future for this item
                     .andThen(result -> resultsByItem.put(item, result)) // Append the result to the map
        ).toArray(CompletableFuture[]::new)
);
allWork.join();
// Your futureMap is completed.

這將替換問題中的整個代碼。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM