future.get() 必须配合超时使用,否则会无限阻塞;isdone()/iscancelled() 仅判状态不能取结果;completablefuture 支持链式编排、回调与组合,是现代异步开发首选。

Future.get() 会阻塞当前线程,必须配合超时使用
调用 Future.get() 是获取结果的最直接方式,但它会一直阻塞,直到任务完成或抛出异常。生产环境几乎从不裸用无参版本,否则主线程可能永久卡住。
- 务必使用带超时的重载:
future.get(3, TimeUnit.SECONDS),避免无限等待 - 超时后抛出
TimeoutException,需显式捕获并处理(如降级、重试、记录告警) - 任务本身抛异常时,
get()会包装为ExecutionException,原始异常在.getCause()中
isDone() 和 isCancelled() 只能判断状态,不能取结果
这两个方法常被误当作“安全获取结果”的替代方案——其实它们只返回布尔值,对结果本身毫无帮助。轮询 isDone() 再调 get() 属于典型忙等待,浪费 CPU 且延迟不可控。
- 除非有特殊调度逻辑(如配合自旋+退避),否则不建议手动轮询
-
isCancelled()在任务被cancel(true)后才为true,但已开始执行的任务未必真正中断 - 即使
isDone() == true,仍需调用get()才能拿到值或感知异常
CompletableFuture 比 Future 更适合实际业务场景
原生 Future 接口功能极其有限:无法链式编排、不能回调、不支持组合、异常处理笨重。Java 8 引入的 CompletableFuture 才是现代异步开发的事实标准。
- 用
thenApply()、thenAccept()做结果后续处理,无需阻塞取值 -
exceptionally()或handle()统一收口异常,比层层 try-catchget()干净得多 - 多个异步任务合并用
allOf()/anyOf(),原生Future完全做不到 - 注意
CompletableFuture默认使用ForkJoinPool.commonPool(),高并发 I/O 场景建议显式指定线程池
submit(Callable) 返回的 Future 和 execute(Runnable) 的区别
很多人混淆两者返回类型:只有 submit(Callable<t>)</t> 返回带泛型的 Future<t>,能取结果;<code>execute(Runnable) 或 submit(Runnable) 返回的是 Future>,get() 永远返回 null。
立即学习“Java免费学习笔记(深入)”;
- 若任务无返回值,别强行用
Future.get(),它除了确认执行完毕没别的意义 -
submit(Runnable, result)可指定返回值,但通常不如直接用Callable直观 - 线程池拒绝策略触发时,
submit()仍会返回Future,但后续get()会立即抛RejectedExecutionException
Future,上层 Web 层却用同步 MVC 框架,这种混合模型最容易出超时和线程饥饿问题。









