Guava:仅在请求时转换ListenableFuture的实现方法
解决ListenableFuture串联时的延迟执行需求
首先得明确你遇到的核心问题:当原ListenableFuture已经完成时,调用Futures.transform会立刻执行传入的转换逻辑,哪怕你根本没去操作新生成的future。而你想要的是——只有当原future被主动触发(比如调用get()、添加Listener),或者新future被实际使用时,才执行doSomething。
下面给你两种靠谱的解决思路:
方案一:用Supplier延迟创建转换后的Future
利用Guava的Suppliers.memoize来包装转换逻辑,只有当你真正需要新future的时候,才会触发transform操作,进而执行doSomething。
import com.google.common.base.Suppliers; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import java.util.function.Function; // 原future ListenableFuture<Result> respFuture = ...; // 用memoized Supplier包装转换逻辑,确保只创建一次 var lazyTransformedFuture = Suppliers.memoize(() -> Futures.transform(respFuture, (Function<Result, Another>) result -> { // 这个doSomething只会在第一次获取lazyTransformedFuture.get()时才会执行(如果respFuture已完成) // 或者等respFuture完成后执行(如果respFuture还在运行) doSomething(); return createAnotherResult(result); }) ); // 只有当你需要使用新future时,才调用get() ListenableFuture<Another> anotherFuture = lazyTransformedFuture.get(); // 此时,只有当你调用anotherFuture.get()或者给它加Listener时,doSomething才会触发
这个方案的好处是简单,利用Guava现有API就能实现,不需要自己写包装类。
方案二:自定义懒加载的ListenableFuture
如果需要更灵活的控制,可以自己实现一个ForwardingListenableFuture,只有当新future被调用get()或者添加Listener时,才会关联原future的转换逻辑。
import com.google.common.util.concurrent.ForwardingListenableFuture; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import java.util.function.Function; public class LazyTransformedFuture<Input, Output> extends ForwardingListenableFuture<Output> { private final ListenableFuture<Input> originalFuture; private final Function<Input, Output> transformFunction; private volatile ListenableFuture<Output> delegate; public LazyTransformedFuture(ListenableFuture<Input> originalFuture, Function<Input, Output> transformFunction) { this.originalFuture = originalFuture; this.transformFunction = transformFunction; } @Override protected ListenableFuture<Output> delegate() { // 双重检查锁,确保只初始化一次 if (delegate == null) { synchronized (this) { if (delegate == null) { delegate = Futures.transform(originalFuture, transformFunction); } } } return delegate; } } // 使用方式 ListenableFuture<Another> lazyAnotherFuture = new LazyTransformedFuture<>(respFuture, result -> { doSomething(); return createAnotherResult(result); }); // 只有当调用lazyAnotherFuture.get()或者addListener时,才会触发transform和doSomething
这个方案的优势是封装性更好,调用方不需要关心Supplier的存在,直接使用future即可。
最后再强调一下:如果原future还处于未完成状态,哪怕你直接调用Futures.transform,转换逻辑也不会立即执行——只有当原future完成时才会跑。你遇到的“立即执行”场景,大概率是原future已经完成了,这时候transform会立刻执行转换逻辑,而上面的两种方案就能解决这个问题。
内容的提问来源于stack exchange,提问作者ElyashivLavi
相关产品推荐
相关产品推荐

