You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现当任一CompletableFuture返回可用MyService时完成的Future?

如何从CompletableFuture列表中获取第一个可用的MyService实例?

你说得对,CompletableFuture.anyOf()确实能监听第一个完成的Future,但它不会帮你过滤结果是否符合isAvailable() == true的条件。我们可以通过对每个Future添加过滤逻辑,再结合anyOf()来实现需求,同时还要处理“所有Future都完成但没有可用实例”的边界情况。

核心思路

  1. 转换每个Future:把原始的CompletableFuture<MyService>转换成新的Future——只有当返回的MyService实例可用时,这个新Future才会完成;如果不可用,就让它保持未完成状态(这样anyOf()会忽略它,继续等待其他符合条件的Future)。
  2. 监听第一个符合条件的Future:用anyOf()监听所有转换后的Future,拿到第一个完成的结果。
  3. 处理边界情况:当所有原始Future都完成但没有找到可用实例时,让最终的Future抛出异常,避免无限等待。

完整实现代码

import java.util.List;
import java.util.NoSuchElementException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;

public class FutureUtils {

    public static CompletableFuture<MyService> findFirstAvailable(List<CompletableFuture<MyService>> futures) {
        // 空列表直接返回失败
        if (futures.isEmpty()) {
            return CompletableFuture.failedFuture(new IllegalArgumentException("No service futures provided"));
        }

        // 转换每个原始Future:仅当实例可用时才完成新Future
        List<CompletableFuture<MyService>> filteredFutures = futures.stream()
                .map(future -> 
                    // 先处理原始Future的异常(可选,根据你的错误处理需求调整)
                    future.exceptionally(ex -> {
                        // 这里可以选择返回不可用实例,或者让Future直接失败
                        // 示例:异常视为服务不可用
                        return new MyService(false);
                    })
                    .thenCompose(service -> {
                        if (service.isAvailable()) {
                            // 服务可用,返回已完成的Future
                            return CompletableFuture.completedFuture(service);
                        } else {
                            // 服务不可用,返回一个未完成的Future(让anyOf忽略它)
                            return new CompletableFuture<>();
                        }
                    })
                )
                .toList();

        // 监听第一个完成的可用服务Future
        CompletableFuture<Object> firstAvailable = CompletableFuture.anyOf(filteredFutures.toArray(new CompletableFuture[0]));

        // 当所有原始Future都完成后,检查是否找到可用服务,否则触发失败
        CompletableFuture<Void> allOriginalDone = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
        allOriginalDone.thenRun(() -> {
            if (!firstAvailable.isDone()) {
                firstAvailable.completeExceptionally(new NoSuchElementException("No available MyService found in all completed futures"));
            }
        });

        // 转换回MyService类型,并统一异常包装
        return firstAvailable.thenApply(obj -> (MyService) obj)
                .exceptionally(throwable -> {
                    throw new CompletionException("Failed to find available MyService", throwable);
                });
    }

    // 你的MyService类(示例)
    public static class MyService {
        private final boolean available;

        public MyService(boolean available) {
            this.available = available;
        }

        public boolean isAvailable() {
            return available;
        }
    }
}

代码关键点解释

  • 异常处理:在转换Future时用exceptionally()捕获原始Future的异常,你可以根据业务需求调整——比如把异常视为服务不可用,或者直接让过滤后的Future失败(返回CompletableFuture.failedFuture(ex))。
  • 未完成Future的处理:对于不可用的服务,我们返回一个未完成的CompletableFuture,这样anyOf()会跳过它,继续等待其他符合条件的结果。
  • 边界情况处理:通过allOf()监听所有原始Future的完成状态,一旦全部完成且还没找到可用服务,就主动让firstAvailable抛出异常,避免程序无限等待。

示例用法

import java.util.Arrays;
import java.util.concurrent.CompletableFuture;

public class Main {
    public static void main(String[] args) {
        List<CompletableFuture<FutureUtils.MyService>> serviceFutures = Arrays.asList(
                // 模拟不可用服务
                CompletableFuture.supplyAsync(() -> new FutureUtils.MyService(false)),
                // 模拟第一个可用服务
                CompletableFuture.supplyAsync(() -> new FutureUtils.MyService(true)),
                // 模拟不可用服务
                CompletableFuture.supplyAsync(() -> new FutureUtils.MyService(false))
        );

        FutureUtils.findFirstAvailable(serviceFutures)
                .thenAccept(service -> System.out.println("找到可用服务!"))
                .exceptionally(ex -> {
                    System.err.println("未找到可用服务:" + ex.getMessage());
                    return null;
                });

        // 主线程等待一下结果(实际应用中不需要,这里只是为了演示)
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}

这个实现既高效又能覆盖各种场景,完美匹配你的需求。

内容的提问来源于stack exchange,提问作者Jade Dezo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:14:19