future.get()会阻塞当前线程直至任务完成,必须配合超时和异常处理使用;其缺乏回调、组合等能力,推荐用completablefuture替代。

Future.get() 会阻塞当前线程直到任务完成
调用 Future.get() 是最直接的取结果方式,但它不是“非阻塞”的——如果任务还没结束,当前线程会一直挂起等待。这在 UI 线程或高并发服务中极易引发响应延迟甚至超时。
实操建议:
- 永远配合超时使用:
future.get(3, TimeUnit.SECONDS),避免无限等待 - 必须捕获
InterruptedException和ExecutionException:前者说明线程被中断,后者包装了任务内部抛出的真实异常 - 若任务已取消,
get()会抛出CancellationException
isDone() 和 isCancelled() 用于安全轮询状态
想避免阻塞又需要知道结果是否就绪,不能靠 while(!future.isDone()) Thread.sleep(10) 这种忙等——既浪费 CPU,又不精确。更合理的做法是结合回调或调度机制。
常见误用场景:
立即学习“Java免费学习笔记(深入)”;
- 在循环里高频调用
isDone()+get()(没加 try-catch)→ 一旦任务失败,下一次 get 就重复抛异常 - 把
isCancelled()当作!isDone()的反义 → 实际上任务可能已完成但未取消,也可能已取消但尚未完成(如正在清理资源) - 忽略
Future.cancel(true)的布尔参数含义:传true才会尝试中断运行中的线程
CompletableFuture 替代 Future 是更现代的选择
Future 接口本身没有链式处理、组合、异常恢复等能力,所有逻辑都得手动轮询+判断。Java 8 引入的 CompletableFuture 才是实际开发中真正可用的异步抽象。
关键差异点:
-
Future无法注册回调;CompletableFuture支持thenApply、whenComplete、exceptionally等非阻塞响应式操作 -
Future不支持多个任务编排;CompletableFuture.allOf()和CompletableFuture.anyOf()可自然组合依赖关系 -
Future没有默认线程池配置;CompletableFuture的异步方法(如supplyAsync)可显式传入Executor,避免挤占ForkJoinPool.commonPool()
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
// 模拟耗时操作
try { Thread.sleep(1000); } catch (InterruptedException e) { }
return "done";
}, customExecutor);
future.thenAccept(result -> System.out.println("Received: " + result))
.exceptionally(throwable -> {
System.err.println("Failed: " + throwable.getMessage());
return null;
});
submit(Callable) 返回的 Future 与 execute(Runnable) 的根本区别
ExecutorService.submit() 返回 Future,而 execute() 没有返回值——这不是设计疏漏,而是语义差异:前者承诺“有结果可取”,后者只表示“已安排执行”。
容易踩的坑:
- 用
submit(Runnable)→ 返回的Future调用get()得到的是null,不是异常,但很多人误以为是执行失败 - 向
submit()传Runnable时,若需返回值,应改用Callable或包装成CompletableFuture.completedFuture(value) -
Future.cancel(true)对Runnable任务无效(除非它自己响应中断),但对Callable中主动检查Thread.interrupted()的逻辑才真正起作用
Future 接口本身解决,得靠任务建模和执行策略设计。










