如何创建仅在调用CompletableFuture::get时才执行计算的CompletableFuture?
实现CompletableFuture的惰性求值
CompletableFuture默认调用supplyAsync这类方法时会立刻把任务提交到线程池执行,要实现调用get()/join()时才启动计算的惰性效果,你可以试试这几种方式:
用Supplier+缓存封装按需执行逻辑
先把计算逻辑放在Supplier里,不直接创建CompletableFuture,直到需要获取结果时才触发任务,同时加个缓存避免重复执行:// 定义耗时的计算逻辑 private Supplier<String> lazyCompute = () -> { // 这里写你的计算代码 return "计算完成的结果"; }; private CompletableFuture<String> cachedFuture; public String getLazyResult() throws InterruptedException, ExecutionException { if (cachedFuture == null) { // 第一次调用get时才启动任务 cachedFuture = CompletableFuture.supplyAsync(lazyCompute); } return cachedFuture.get(); }这种方式不用自定义类,代码简单,适合大多数场景。
自定义惰性CompletableFuture子类
如果需要更通用的封装,可以自己写一个子类,重写get/join方法,确保只有在调用这些方法时才启动计算:public class LazyCompletableFuture<T> extends CompletableFuture<T> { private final Supplier<T> task; private volatile boolean isStarted = false; public LazyCompletableFuture(Supplier<T> task) { this.task = task; } @Override public T get() throws InterruptedException, ExecutionException { startTaskIfNeeded(); return super.get(); } @Override public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { startTaskIfNeeded(); return super.get(timeout, unit); } @Override public T join() { startTaskIfNeeded(); return super.join(); } private void startTaskIfNeeded() { if (!isStarted) { synchronized (this) { if (!isStarted) { // 启动任务并把结果/异常传递给当前Future CompletableFuture.supplyAsync(task) .whenComplete((result, ex) -> { if (ex != null) { completeExceptionally(ex); } else { complete(result); } }); isStarted = true; } } } } }使用时直接实例化,调用get之前任务不会执行:
LazyCompletableFuture<String> lazyFuture = new LazyCompletableFuture<>(() -> "惰性计算结果"); // 此时任务未启动 String result = lazyFuture.get(); // 调用get时才开始计算第三方替代方案(可选)
如果允许引入外部依赖,Guava的ListenableFuture天生支持惰性执行,需要手动绑定Executor来触发任务,不过如果不想加依赖,前面两种原生方案足够用。
内容的提问来源于stack exchange,提问作者davidalayachew
相关产品推荐
相关产品推荐

