FutureTask不支持直接轮询,需结合isDone()与get(0, TimeUnit.NANOSECONDS)实现非阻塞轮询:先快速判断完成状态,再瞬时获取结果,未完成时休眠避免空转;纯busy-wait会导致CPU飙升且无法捕获异常。

FutureTask 本身不提供轮询获取结果的机制,它设计上是阻塞式等待(get())或带超时的等待,但可以通过循环调用 isDone() + get(0, TimeUnit.NANOSECONDS) 实现非阻塞轮询 —— 关键在于避免长时间阻塞,同时及时感知完成状态。
轮询的核心逻辑:用超时 get 配合完成状态判断
直接反复调用无参 get() 会一直阻塞,不可用于轮询。正确做法是:
- 先用
isDone()快速判断任务是否已完成(开销极小) - 若已完成,再调用
get(0, TimeUnit.NANOSECONDS)瞬时获取结果(此时不会阻塞) - 若未完成,可选择休眠一小段时间(如 10ms),再重试,避免空转耗 CPU
典型轮询代码示例
以下是一个安全、低开销的轮询实现:
FutureTask<String> task = new FutureTask<>(() -> {
Thread.sleep(1000);
return "done";
});
new Thread(task).start();
while (!task.isDone()) {
try {
// 尝试零等待获取结果(仅在已完成时返回,否则抛 TimeoutException)
String result = task.get(0, TimeUnit.NANOSECONDS);
System.out.println("Result: " + result);
break;
} catch (TimeoutException e) {
// 未完成,继续轮询(可加 sleep 控制频率)
Thread.sleep(10);
} catch (ExecutionException | InterruptedException e) {
throw new RuntimeException(e);
}
}
注意 get(0, …) 的行为细节
get(0, unit) 并非“立即返回 null”,而是:
立即学习“Java免费学习笔记(深入)”;
- 任务已结束 → 立即返回结果或抛出 ExecutionException
- 任务未结束 → 立即抛出 TimeoutException(不是返回 null 或 false)
- 因此必须捕获
TimeoutException来区分“未完成”和“异常”
为什么不建议纯 busy-wait(空循环)
仅靠 while(!task.isDone()) {} 不做任何延迟或 get 尝试,会导致:
- CPU 占用率飙升(尤其多线程环境下)
- 无法及时拿到结果(
isDone()返回 true 后仍需调用get()才能取值) - 忽略执行异常(ExecutionException 只在 get 时暴露)
轮询本质是折中方案:比阻塞更灵活,比回调更简单,适用于轻量监控或短周期状态检查场景。


















