FutureTask 的核心在于用 volatile int state 状态机和 LockSupport/wait/notify 机制,将执行与结果获取串成可预测生命周期链;状态流转驱动 run()/get()/cancel() 行为,实现 Runnable/Callable 到 Future 的语义桥接。
futuretask 的“桥接精髓”不在它同时实现了两个接口,而在于它用一个轻量状态机(volatile int state)和配套的同步等待机制(locksupport.park / wait/notify),把“执行动作”和“结果获取”这两个异步阶段串成一条可预测、可控制的生命周期链。
状态驱动,不是接口堆叠
Runnable 要求有 run(),Future 要求能 get()——但光实现方法签名没用。FutureTask 的核心是内部 state 字段,取值如 NEW → COMPLETING → NORMAL/EXCEPTIONAL/CANCELLED。所有行为都围绕这个状态流转:
-
run()只在state == NEW时真正执行任务体,否则直接返回(幂等性) -
get()检查状态:未完成就阻塞;已完成就立即返回结果或抛异常 -
cancel(true)不是“杀死线程”,而是设中断标志 + 尝试interrupt(),是否生效取决于任务体是否检查Thread.interrupted()
统一调度与统一获取的落点
它让 Runnable/Callable 这类“任务描述”具备了 Future 的语义能力,从而可以无缝接入 ExecutorService:
- 传给
executor.submit(task):线程池调用task.run()执行,你随时用task.get()拿结果 - 不用再手动维护回调、共享变量或 Handler —— 状态和同步全由 FutureTask 自己管
- 即使是
new FutureTask(runnable, result)这种无返回值任务,也能通过get()获取预设默认值(仅当任务完成才返回,否则阻塞)
避免常见误用的关键细节
桥接失效,往往源于对状态逻辑的忽视:
- 手动多次调用
run():可能触发重复执行(只应由线程或线程池调度) -
get()卡住:说明任务没完成且没异常,要检查是不是任务体没结束、没设置结果、或被中断后未处理 -
isDone() == false但run()已返回:可能是任务抛了未捕获异常,导致状态卡在 COMPLETING -
submit(runnable, result)和new FutureTask(runnable, result)返回值逻辑不同:前者 get 总返回 result;后者只在任务完成后才返回
它不是语法糖,而是一套内聚的状态协议——把“谁来跑”和“结果在哪”这两个问题,压进同一个对象的生命周期里。

















