FutureTask 是 Java 中实现 Runnable 和 Future 接口的异步任务封装,支持取消、状态查询与阻塞获取结果;可提交至 ExecutorService 执行,提供比 submit(Callable) 更细粒度的生命周期控制,但仅能执行一次且状态不可重置。

FutureTask 是 Java 并发编程中一个可取消、可重复获取结果的异步计算任务封装,它本身实现了 Runnable 和 Future 接口,能直接提交给 ExecutorService 执行,同时支持手动控制执行状态和获取计算结果。
FutureTask 的核心作用
它把一个 Callable(或 Runnable)包装成一个可被线程池调度、可查询状态、可阻塞获取结果的任务单元。相比直接用 submit(Callable),FutureTask 提供了更细粒度的生命周期控制,比如在提交前就调用 cancel() 预取消,或多次调用 get() 而不重复执行逻辑。
- 构造时传入 Callable,内部自动处理异常捕获与结果缓存
- 执行完成后,get() 返回结果;若未完成则阻塞等待(可设超时)
- cancel(true) 可尝试中断正在运行的线程,cancel(false) 仅拒绝未开始的任务
与 ExecutorService 的典型配合方式
ExecutorService 不直接接受 FutureTask 作为参数,但 FutureTask 实现了 Runnable,因此可用 execute() 提交;也可用 submit() 提交,此时返回的 Future 就是它自己(因为 FutureTask 自身就是 Future)。
- 用 execute(futureTask):适合不需要结果、只关心是否执行完毕的场景
- 用 submit(futureTask):返回值仍是该 FutureTask,便于后续调用 get() 或 isDone()
- 避免重复 submit 同一个 FutureTask 实例——它只能执行一次,重复提交会抛 RejectedExecutionException
实际使用中的关键细节
FutureTask 的状态机是串行的:NEW → COMPLETING → NORMAL/EXCEPTIONAL/CANCELLED。一旦进入终态,就不能再触发执行,也不能重置。这点容易被忽略,导致“任务没反应”或“get() 一直阻塞”。
立即学习“Java免费学习笔记(深入)”;
- 创建后必须显式提交到线程池,它不会自动运行
- 若构造时传入的 Callable 抛出异常,get() 会包装为 ExecutionException,需捕获并 getCause()
- 多个线程并发调用同一个 FutureTask 的 get() 是安全的,结果只会计算一次
- 不建议在 get() 中无限制等待,应配合 timeout 使用,防止线程长时间挂起
一个轻量级示例
以下代码演示如何用 FutureTask + FixedThreadPool 实现带超时的结果获取:
ExecutorService pool = Executors.newFixedThreadPool(2);
FutureTask<String> task = new FutureTask<>(() -> {
Thread.sleep(1000);
return "done";
});
pool.execute(task); // 或 pool.submit(task)
try {
String result = task.get(2, TimeUnit.SECONDS); // 最多等2秒
System.out.println(result);
} catch (TimeoutException e) {
System.out.println("timeout");
} catch (ExecutionException e) {
e.getCause().printStackTrace();
} finally {
pool.shutdown();
}


















