Skip to Content
面试题库Juc[面试题] Callable、Future、FutureTask 之间是什么关系?

[面试题] Callable、Future、FutureTask 之间是什么关系?

📖 版块 A:知识讲解版 (温故知新)

  • Callable

    1. 表示一个有返回值、可抛异常的异步任务。
    2. 核心方法是 call()
  • Future

    1. 表示一个异步结果占位符
    2. 可以查询任务是否完成、是否取消,以及通过 get() 获取结果。
  • FutureTask

    1. 是一个把 CallableFuture 连接起来的实现类。
    2. 它既实现了 Runnable,又实现了 Future
    3. 因此既可以丢给线程执行,也可以在未来拿结果。
  • 三者关系

    • Callable 负责描述“要做什么”。
    • Future 负责描述“结果怎么拿”。
    • FutureTask 负责把“任务”和“结果”包装成一个可执行对象。
  • 使用方式

    1. ExecutorService.submit(Callable) 会返回 Future
    2. 手动创建 FutureTask 后,既可以 new Thread(futureTask).start(),也可以交给线程池执行。
  • 局限性

    • Future#get() 通常是阻塞的。
    • 多任务编排能力弱,回调和异常链路不够优雅。

🎤 版块 B:面试实战版 (高手逐字稿)

Q:Callable、Future、FutureTask 之间是什么关系?

💬 高手逐字稿

这三个类其实是在解决同一件事的不同环节,也就是 Java 里最基础的一套异步编程模型。

先看 Callable,它描述的是一个“可返回结果的任务”。和 Runnable 最大的区别有两个:第一,它有返回值;第二,它允许抛受检异常。所以凡是任务执行完之后,我还想拿到计算结果,或者我不想把异常吞掉,都会更倾向用 Callable

然后是 Future。它并不负责执行任务,而是表示一个“未来会完成的结果”。你可以把它理解成一个异步占位符。线程池把任务扔出去之后,先给你一个 Future,你后面可以通过 isDone() 看任务结束没有,通过 cancel() 取消任务,通过 get() 阻塞等待结果。

真正把这两者连起来的是 FutureTask。它既实现了 Runnable,说明它可以被线程或者线程池执行;又实现了 Future,说明它本身又能持有执行结果。所以 FutureTask 本质上就是一个“可执行的异步结果容器”。我们把 Callable 包进 FutureTask 之后,这个对象就既知道“怎么执行任务”,也知道“怎么保存和返回结果”。

如果从链路上讲,就是:

  • Callable 定义任务逻辑;
  • FutureTask 包装任务并承接结果;
  • Future 暴露统一的结果获取能力。

但这套模型也有明显局限。最大的问题就是 Future#get() 很容易把异步重新写回同步,因为一调用就阻塞了。第二,它不擅长做多个异步任务之间的组合、回调和异常传播。所以在现代业务代码里,简单场景我会用 Future,但只要涉及任务编排,通常会切到 CompletableFuture

最后更新于:
⏱️

登录后开始阅读

当前 MVP 版本只开放邮箱密码登录注册。完成登录后即可进入面试题内容。

还没有账号?先去注册