ListenableFuture的使用和原理

本文深入解析ListenableFuture在Google Guava框架中的应用,对比FutureTask,重点介绍了如何使用ListenableFuture进行异步任务处理,包括任务提交、回调函数设置及执行原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

java中有几种实现异步的方式(FutureTask/ListenableFuture/CompletableFuture)
这篇介绍的是ListenableFuture,相比FutureTask,本质上只是增加了任务的回调函数,这个是google框架里面的一个东西,我用的版本是guava-27.0-jre.jar
首先还是说使用:

public class ListenableFutureTest {
    public static void main(String[] args) {
        testListenFuture();
    }

    public static void testListenFuture() {
        System.out.println("主线程start");
        ListeningExecutorService pool = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(5));

        Task task1 = new Task();
        task1.args = "task1";
        Task task2 = new Task();
        task2.args = "task2";
        ListenableFuture<String> future = pool.submit(task1);
        ListenableFuture<String> future2 = pool.submit(task2);

        future2.addListener(() -> System.out.println("addListener 不能带返回值"), pool);

        /**
         * FutureCallBack接口可以对每个任务的成功或失败单独做出响应
         */
        FutureCallback<String> futureCallback = new FutureCallback<String>() {
            @Override
            public void onSuccess(String result) {
                System.out.println("Futures.addCallback 能带返回值:" + result);
            }
            @Override
            public void onFailure(Throwable t) {
                System.out.println("出错,业务回滚或补偿");
            }
        };

        //为任务绑定回调接口
        Futures.addCallback(future, futureCallback, pool);
        System.out.println("主线程end");
    }
}

class Task implements Callable<String> {
    String args;
    @Override
    public String call() throws Exception {
        Thread.sleep(1000);
        System.out.println("任务:" + args);
        return "dong";
    }
}

future2.addListener(() -> System.out.println(“addListener 不能带返回值”), pool);
Futures.addCallback(future, futureCallback, pool);
两种方法都可以,一会说一下原理,其实Futures.addCallback里面也是调用addListener
然后从上到下说一下原理:
上一篇直接用的是Thread(futureTask).start()去执行一个任务
这一篇用了java中的线程池-ThreadPoolExecutor,里面主要是使用execute去执行任务的
MoreExecutors.listeningDecorator就是包装了一下ThreadPoolExecutor,目的是为了使用ListenableFuture

private static class ListeningDecorator extends AbstractListeningExecutorService {
        private final ExecutorService delegate;

        ListeningDecorator(ExecutorService delegate) {
            this.delegate = (ExecutorService)Preconditions.checkNotNull(delegate);
        }

        public final void execute(Runnable command) {
            this.delegate.execute(command);
        }
    }

在这里插入图片描述
在这里插入图片描述
这里的delegate就是ThreadPoolExecutor
虽然还重写了execute,不过还是直接调用ThreadPoolExecutor里面的execute
ListeningExecutorService pool=MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(5));
这样一个执行器就被new出来了,现在需要往里面放任务了
ListenableFuture future = pool.submit(task1);看看submit代码

public <T> ListenableFuture<T> submit(Callable<T> task) {
        return (ListenableFuture)super.submit(task);
    }

然后调用父类的submit

public <T> Future<T> submit(Callable<T> task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task);
        execute(ftask);
        return ftask;
    }

这里会调用重写的newTaskFor

protected final <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
        return TrustedListenableFutureTask.create(callable);
    }
class TrustedListenableFutureTask<V> extends TrustedFuture<V> implements RunnableFuture<V> {
    private volatile InterruptibleTask<?> task;
    
    static <V> TrustedListenableFutureTask<V> create(Callable<V> callable) {
        return new TrustedListenableFutureTask(callable);
    }

    TrustedListenableFutureTask(Callable<V> callable) {
        this.task = new TrustedListenableFutureTask.TrustedFutureInterruptibleTask(callable);
    }

    public void run() {
        InterruptibleTask localTask = this.task;
        if (localTask != null) {
            localTask.run();
        }

        this.task = null;
    }
}    

创建了一个TrustedListenableFutureTask,里面有个task是TrustedFutureInterruptibleAsyncTask
这里重写了Runnable的run方法,调用的就是这个task得run方法(也就是我们真正的任务)

private final class TrustedFutureInterruptibleAsyncTask extends InterruptibleTask<ListenableFuture<V>> {
        private final AsyncCallable<V> callable;

        TrustedFutureInterruptibleAsyncTask(AsyncCallable<V> callable) {
            this.callable = (AsyncCallable)Preconditions.checkNotNull(callable);
        }
    }

在这里插入图片描述
RunnableFuture ftask = newTaskFor(task);
所以这里返回的是一个RunnableFuture,本质其实是TrustedListenableFutureTask(每个任务都有这么一个future)
execute(ftask);
然后会调用execute,让线程池中某个线程去执行

public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        int c = ctl.get();
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        else if (!addWorker(command, false))
            reject(command);
    }

再说一下addListener,其实就是给任务增加一个回调函数
future2.addListener(() -> System.out.println(“addListener 不能带返回值”), pool);
这里调用的是TrustedListenableFutureTask的addListener
实际上调用的是父类AbstractFuture的addListener

public void addListener(Runnable listener, Executor executor) {
    checkNotNull(listener, "Runnable was null.");
    checkNotNull(executor, "Executor was null.");
    if (!isDone()) {
      Listener oldHead = listeners;
      if (oldHead != Listener.TOMBSTONE) {
        Listener newNode = new Listener(listener, executor);
        do {
          newNode.next = oldHead;
          if (ATOMIC_HELPER.casListeners(this, oldHead, newNode)) {
            return;
          }
          oldHead = listeners; // re-read
        } while (oldHead != Listener.TOMBSTONE);
      }
    }
    // If we get here then the Listener TOMBSTONE was set, which means the future is done, call
    // the listener.
    executeListener(listener, executor);
  }

如果这个任务已经完成,执行executeListener

private static void executeListener(Runnable runnable, Executor executor) {
        try {
            executor.execute(runnable);
        } catch (RuntimeException var3) {
            log.log(java.util.logging.Level.SEVERE, "RuntimeException while executing runnable " + runnable + " with executor " + executor, var3);
        }

    }

这里就是调用执行器的execute方法,相当于给线程池扔一个任务,毕竟回调函数也是一个任务

如果这个任务没有完成,那么把回调函数保存起来,用一个链表保存,链表的头结点就是listener,这个listener里面的回调函数在哪执行呢?在任务执行完之后,我文章最后再说这个问题。
ATOMIC_HELPER.casListeners(this, oldHead, newNode)是给listener赋值的原子操作。

private static final class Listener {
    static final Listener TOMBSTONE = new Listener(null, null);
    final Runnable task;
    final Executor executor;

    // writes to next are made visible by subsequent CAS's on the listeners field
    @Nullable Listener next;

    Listener(Runnable task, Executor executor) {
      this.task = task;
      this.executor = executor;
    }
  }

为什么要用链表呢?因为一个任务可以有多个回调函数

再来看看Futures.addCallback(future, futureCallback, pool);

public static <V> void addCallback(
      final ListenableFuture<V> future,
      final FutureCallback<? super V> callback,
      Executor executor) {
    Preconditions.checkNotNull(callback);
    future.addListener(new CallbackListener<V>(future, callback), executor);
  }

底层用CallbackListener封装了一下,还是调用了addListener
为什么要封装一下呢?因为要拿到任务的返回值

private static final class CallbackListener<V> implements Runnable {
    final Future<V> future;
    final FutureCallback<? super V> callback;

    CallbackListener(Future<V> future, FutureCallback<? super V> callback) {
      this.future = future;
      this.callback = callback;
    }

    @Override
    public void run() {
      final V value;
      try {
        value = getDone(future);
      } catch (ExecutionException e) {
        callback.onFailure(e.getCause());
        return;
      } catch (RuntimeException | Error e) {
        callback.onFailure(e);
        return;
      }
      callback.onSuccess(value);
    }
  }

在这个run方法里面就调用getDone等待返回值,如果有异常就调用callback.onFailure,没有异常就调动callback.onSuccess(value);
这两个方法都是你传入的,这样就能接收到任务的返回值了

 public static <V> V getDone(Future<V> future) throws ExecutionException {
    checkState(future.isDone(), "Future was expected to be done: %s", future);
    return getUninterruptibly(future);
  }
  
public static <V> V getUninterruptibly(Future<V> future) throws ExecutionException {
    boolean interrupted = false;
    try {
      while (true) {
        try {
          return future.get();
        } catch (InterruptedException e) {
          interrupted = true;
        }
      }
    } finally {
      if (interrupted) {
        Thread.currentThread().interrupt();
      }
    }
  }

future.get()就是到等待任务执行结束

现在接着说listener中的回调函数在哪执行的

private final class TrustedFutureInterruptibleTask extends InterruptibleTask<V> {
    private final Callable<V> callable;

    @Override
    void afterRanInterruptibly(V result, Throwable error) {
      if (error == null) {
        TrustedListenableFutureTask.this.set(result);
      } else {
        setException(error);
      }
    }
  }

在任务执行完之后,这里调用了set方法

protected boolean set(@Nullable V value) {
    Object valueToSet = value == null ? NULL : value;
    if (ATOMIC_HELPER.casValue(this, null, valueToSet)) {
      complete(this);
      return true;
    }
    return false;
  }

然后又调用了comlete

private static void complete(AbstractFuture<?> future) {
    Listener next = null;
    outer:
    while (true) {
      future.releaseWaiters();
      next = future.clearListeners(next);
      future = null;
      while (next != null) {
        Listener curr = next;
        next = next.next;
        Runnable task = curr.task;
        if (task instanceof SetFuture) {
          SetFuture<?> setFuture = (SetFuture<?>) task;
          future = setFuture.owner;
          if (future.value == setFuture) {
            Object valueToSet = getFutureValue(setFuture.future);
            if (ATOMIC_HELPER.casValue(future, setFuture, valueToSet)) {
              continue outer;
            }
          }
          // other wise the future we were trying to set is already done.
        } else {
          executeListener(task, curr.executor);
        }
      }
      break;
    }
  }

就是在这里执行完所有的回调函数

<think>我们正在讨论的是Java中的ListenableFuture,特别是关于类型转换(ListenableFuture<?>)的作用原理。根据引用[1][2][3][4]:ListenableFuture是GoogleGuava库提供的一种增强型Future,它允许注册回调函数,在异步操作完成时自动调用,从而实现非阻塞的异步编程。用户的问题:理解ListenableFuture的用途及(ListenableFuture<?>)类型转换的意义。回答结构:1.解释ListenableFuture的用途优势。2.分析类型转换(ListenableFuture<?>)的作用原理。注意:引用[2]提到ListenableFutureCompletableFuture的相似性,引用[3][4]具体说明了ListenableFuture使用方法。具体回答:</think>### Java `ListenableFuture` 用途及类型转换解析 `ListenableFuture` 是 Google Guava 库提供的增强型异步编程工具,核心价值在于**解决传统 `Future` 的阻塞等待问题**,通过回调机制实现非阻塞异步处理。以下结合引用内容详细解析其用途类型转换原理: --- ### 一、`ListenableFuture` 的核心用途 1. **非阻塞结果处理** 与传统 `Future.get()` 的阻塞等待不同(引用[2]),`ListenableFuture` 允许注册回调函数,在异步操作完成时**自动触发结果处理**(引用[3]): ```java ListenableFuture<String> future = executor.submit(task); // 添加回调(非阻塞) Futures.addCallback(future, new FutureCallback<String>() { @Override public void onSuccess(String result) { // 异步结果处理 } @Override public void onFailure(Throwable t) { // 异常处理 } }, executor); ``` 2. **链式调用与组合** 支持将多个异步操作串联(引用[1]),例如: ```java ListenableFuture<A> futureA = taskA(); ListenableFuture<B> futureB = Futures.transformAsync(futureA, a -> taskB(a), executor); ``` 3. **与 `CompletableFuture` 的关系** - `ListenableFuture` 是 Guava 对 `Future` 的扩展(早于 Java 8) - `CompletableFuture` 是 JDK 8+ 的官方实现(引用[2]),两者设计思想相似 - **兼容性价值**:在维护旧系统或深度定制异步流时仍需使用(引用[1][4]) --- ### 二、`(ListenableFuture<?>)` 类型转换的作用与原理 #### ▶ 场景示例 假设有泛型方法返回原始 `ListenableFuture`: ```java public ListenableFuture<?> fetchData() { return executor.submit(() -> {...}); // 返回未指定类型的Future } ``` #### ▶ 类型转换的意义 1. **安全访问具体类型** 当需要操作结果的具体类型时(如 `String`),通过强制转换避免编译错误: ```java ListenableFuture<?> rawFuture = fetchData(); ListenableFuture<String> strFuture = (ListenableFuture<String>) rawFuture; // 现在可安全使用String类型结果 Futures.transform(strFuture, s -> s.length(), executor); ``` 2. **绕过泛型擦除限制** Java 泛型在运行时被擦除(引用[5]),转换实质是**编译器类型检查的妥协**: ```java // 编译时:检查类型约束 // 运行时:所有ListenableFuture都是同一类对象 ``` #### ▶ 转换原理 - **编译阶段**:编译器验证转换的**逻辑合理性**(如目标类型是否可能匹配) - **运行时**:JVM 执行 **`checkcast` 指令**,验证对象实际类型: ```java // 伪代码:运行时检查 if (rawFuture.get() instanceof String) { // 允许操作 } else { throw ClassCastException(); } ``` #### ▶ 风险与规避 | 风险点 | 解决方案 | |------------------------|----------------------------| | `ClassCastException` | 用 `Futures.transform()` 包装转换逻辑 | | 类型污染 | 封装返回类型(如 `ListenableFuture<String>`) | | 链式调用中断 | 使用 `Futures.catchingAsync()` 处理异常 | **安全转换示例**: ```java ListenableFuture<?> rawFuture = fetchData(); // 安全转换:通过transform包装 ListenableFuture<Integer> safeFuture = Futures.transform( rawFuture, obj -> (String) obj, // 显式转换点(集中管理) executor ); ``` --- ### 三、`ListenableFuture` 与 `CompletableFuture` 对比 | 特性 | `ListenableFuture` (Guava) | `CompletableFuture` (JDK 8+) | |---------------------|----------------------------------|----------------------------------| | **回调注册** | `addListener()`/`addCallback()` | `thenApply()`/`thenAccept()` | | **异常处理** | 需手动实现 `onFailure` | 内置 `exceptionally()`/`handle()`| | **组合操作** | 依赖 `Futures` 工具类 | 内置 `thenCompose()`/`allOf()` | | **类型安全** | 依赖强制转换 | 泛型方法保障 | > **最佳实践**:新项目优先使用 `CompletableFuture`,旧系统迁移时可混合使用 `Futures.toCompletableFuture()`(Guava 31.0+ 支持)。 --- ### 总结 1. **`ListenableFuture` 用途** - 非阻塞回调(替代 `Future.get()` 阻塞) - 异步操作链式组合 - 旧代码库兼容性维护(引用[1][4]) 2. **类型转换意义** - 作用:访问具体类型结果,绕过泛型擦除限制 - 原理:编译器类型检查 + 运行时 `checkcast` 验证 - 风险:需用 `Futures.transform()` 等工具规避 `ClassCastException` 3. **演进关系** `Future` → `ListenableFuture` (Guava) → `CompletableFuture` (JDK 8+),三者共同解决异步编程痛点(引用[2][4])。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值