Future.get() 必须配合超时使用,避免线程无限阻塞;isDone()/isCancelled() 仅查状态,不能替代 get();原始 Future 不支持回调,轮询是反模式;submit(Runnable) 返回的 Future 无法获取结果,需用 Callable。

Future.get() 会阻塞当前线程,必须配合超时使用
调用 Future.get() 是最直接的取结果方式,但它默认无限期等待,一旦任务卡住或执行时间不可控,调用线程就会一直挂起。生产环境几乎从不裸用无参 get()。
- 务必使用带超时的重载:
future.get(3, TimeUnit.SECONDS),避免线程被长期占用 - 超时后抛出
TimeoutException,需显式捕获并处理(如降级、重试、记录告警) - 如果任务已取消或执行异常,
get()会包装抛出CancellationException或ExecutionException,不能只 catchException
isDone() 和 isCancelled() 只能查状态,不能代替 get()
这两个方法返回布尔值,常被误当作“安全取值”的替代方案。其实它们只反映任务生命周期状态,和结果内容完全无关。
-
isDone()为 true 仅表示任务已结束(无论成功、失败或取消),但结果可能还没真正计算完(比如刚进入完成状态但尚未设置 outcome 字段) -
isCancelled()为 true 时,get()必然抛CancellationException,此时不应再尝试获取业务数据 - 轮询
isDone()+ 睡眠再重试,属于低效且易出错的 busy-wait,应优先考虑CompletableFuture的回调机制
Future 本身不支持回调,强行轮询或 sleep 是反模式
原始 Future 接口没有 thenApply、whenComplete 这类能力,这是它和 CompletableFuture 的本质区别。很多老项目因不了解这点,写出如下代码:
while (!future.isDone()) {
Thread.sleep(10);
}
这不仅浪费 CPU 和线程资源,还掩盖了真正的异步协调需求。
立即学习“Java免费学习笔记(深入)”;
- 若需事件驱动响应,应直接升级到
CompletableFuture,它实现了Future并扩展了函数式链式操作 - 若必须用原始
Future(如对接旧线程池 API),建议封装一层监听器,或改用ExecutorService.invokeAny()/invokeAll()批量控制 - 注意:
Future实例不是线程安全的,多个线程并发调用get()或cancel()需自行同步
submit(Runnable) 返回的 Future 无法获取返回值
很多人以为只要用了 ExecutorService.submit() 就能拿结果,却忽略了参数类型差异:
-
submit(Runnable task)返回Future>,其get()永远返回null—— 因为Runnable没有返回值 - 要获取计算结果,必须用
submit(Callable,其中task) Callable的call()方法有返回值且可抛受检异常 - 常见错误:把 lambda 写成
() -> { doWork(); }(推断为Runnable),应显式写成() -> { doWork(); return result; }让编译器识别为Callable
Future 很快就会成为瓶颈。别硬扛,该换 CompletableFuture 就换。










