如何将 java Future<V> 转换为 guava ListenableFuture<V>

how to convert java Future<V> to guava ListenableFuture<V>

我需要找到一种方法将 Future 转换为 ListenableFuture。 目前我正在使用 returns Future 的服务,但我需要为其连接一个监听器。 我无法更改服务界面,因为它不属于我。

有没有简单的方法可以做到这一点?

我已经阅读了 guava 文档,但我仍然找不到实现它的方法。

Guava 为这种转换提供了 JdkFutureAdapters 类型。 API 状态

Utilities necessary for working with libraries that supply plain Future instances.

例如

Future<?> future = ...;
ListenableFuture<?> listenable = JdkFutureAdapters.listenInPoolThread(future);

但是你应该小心使用它:当你已经提交任务时,很难模仿可听的未来,因为没有在那里完成挂钩的方法,因此番石榴采用新线程并阻塞在那里直到原始 Future 完成。

Guava Wiki 也 contains some information on this specific case

Future 只是获取接口,而 Guava ListenableFuture 是带有已注册 Runnable 侦听器的 Future 接口 运行 在设置或 setException 时通过 complete()(由 guava AbstractFuture 实现)。

import com.google.common.util.concurrent.AbstractFuture;
import java.util.concurrent.Future;

public class ListenerFuture<V> extends AbstractFuture<V> {

    public ListenerFuture(Future<V> future){
        this.future= future;
    }
    // blocking in future get, then run listener in AbstractFuture set
    public void fireListener(){
        try {
            super.set(future.get());
        }catch (Exception e){
            throw new RuntimeException("guava set ListenableFuture", e);
        }
    }

    private Future<V> future;
}

ListenerFuture<V> response= new ListenerFuture(service.response());
response.addListener(Runnable, Executor);
// pass the ListenableFuture to whom need it
// do something else until who must have service response call the blocking
response.fileListner()

Guava AbstractFuture 有其局限性:

  1. Listener 是列表,但通常只使用 1 个 - 矫枉过正。如果需要多个侦听器,请将其分叉到您的侦听器中或使用消息传递考虑您的设计。
  2. setException 设置return值为Exception,所以用户必须在get()
  3. 时使用instanceof来区分Exception与否
  4. 在 Future pipeline 中,addListener() 的层数过多导致代码难以阅读。

我更喜欢CompletableFuture.supply().thenApply().thenAccept().handle()