futuretask不能重复执行,因state字段单向演进且仅new状态允许cas设runner后执行任务体,否则静默返回;它非thread子类,无start()方法,cancel也不重置state,必须新建实例才能重跑。

FutureTask 不能重复执行,调用多次 run() 或尝试用 start() 启动(它根本不是 Thread 子类)都会被底层状态机直接拒绝——不抛异常,也不执行任务体,只是静默返回。
state 字段控制唯一执行入口
FutureTask 内部用一个 volatile int state 字段标记生命周期,初始值为 NEW。只有当 state == NEW 且成功通过 CAS 将当前线程设为运行者(RUNNER.compareAndSet(this, null, Thread.currentThread()))时,才允许进入任务执行流程。
- 第一次调用
run():state 是 NEW → 执行 callable.call() → 状态跃迁为 COMPLETING → 最终变为 NORMAL 或 EXCEPTIONAL - 第二次调用
run():state 已不是 NEW → 直接 return,什么也不做 - 后续所有调用都跳过任务逻辑,包括异常处理和结果设置
run() 不是普通方法,而是状态跃迁的“门禁”
它的设计意图不是供用户反复调用,而是作为线程调度入口被 Thread 或线程池统一触发。源码中明确写有:
这行判断就是全部拒绝逻辑:只要状态已变,或已有其他线程抢先占位,就立刻退出。
- 没有同步块、没有锁等待、不抛
IllegalStateException - 不记录日志、不告警、不重试——纯粹的“无感拒绝”
- 这种设计保证了幂等性,也避免了并发执行同一任务的风险
为什么不能调用 start()?
FutureTask 实现了 Runnable,但没继承 Thread,所以它没有 start() 方法。
- 写
new Thread(futureTask).start()是合法的,但仅限一次;再次对同一实例这么做,会创建新线程去调用其run(),而该run()仍受 state 控制,大概率直接返回 - 写
futureTask.start()会编译报错:找不到符号 - 试图手动驱动执行,却忽略其状态契约,是多数“任务没跑”“结果为空”问题的根源
cancel(true) 也不会重置 state 允许重跑
调用 cancel(true) 只会把 state 设为 CANCELLED 或 INTERRUPTING,之后再调 run() 依然被拒绝。
- state 是单向演进的:NEW → COMPLETING → NORMAL/EXCEPTIONAL/CANCELLED/INTERRUPTED
- 没有任何 API 能将 state 回退到 NEW,FutureTask 本身不可复用
- 想再次执行相同逻辑,必须新建一个 FutureTask 实例
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











