done()只在任务变为终态(normal、exceptional或cancelled)时触发一次,无论成功、异常或取消;cancel返回true才触发done(),且done()不可调用get()、不宜耗时、不保证执行线程。

done方法只在任务结束时触发,包括取消
done() 是 FutureTask 的受保护回调方法,它在任务状态变为终态(NORMAL、EXCEPTIONAL 或 CANCELLED)后自动调用。也就是说,无论任务是正常完成、抛出异常,还是被主动取消,只要进入终态,done() 就会被执行一次 —— 它不区分成功或失败,只响应“生命周期终结”这个事件。
任务被取消时 done() 的触发条件
cancel(true) 或 cancel(false) 成功调用后,FutureTask 内部会将状态切换为 CANCELLED(若尚未启动)或 INTERRUPTED(若已运行且中断成功),此时 done() 会被调用。关键点在于:cancel 返回 true 才代表任务确实被标记为取消,done() 才会触发;如果 cancel 返回 false(比如任务已运行完毕),done() 不会再调用。
- cancel(true):尝试中断执行线程,若线程响应中断(如 sleep/wait/join 中被唤醒并抛 InterruptedException),状态转为 INTERRUPTED,done() 触发
- cancel(false):仅对未启动任务有效;若任务已在运行,cancel 返回 false,done() 不触发
- 任务刚 submit 还没开始执行就被 cancel,状态直接变为 CANCELLED,done() 立即触发
实战中验证取消后 done() 是否执行
写一个继承 FutureTask 的子类,重写 done() 并打印日志,再配合 cancel(true) 测试:
class LoggingTask extends FutureTask<string> {
public LoggingTask(Callable<string> callable) {
super(callable);
}
@Override
protected void done() {
if (isCancelled()) {
System.out.println("✅ 任务已被取消,done() 已执行");
} else if (isDone() && !isCancelled()) {
System.out.println("✅ 任务已完成,done() 已执行");
}
}
}</string></string>
提交后立即 cancel:
- 若任务尚未执行(线程池空闲或任务排队中),cancel(true) 返回 true → done() 执行 → 输出“任务已被取消”
- 若任务正在执行且包含 Thread.sleep(1000),cancel(true) 中断休眠 → 抛出 InterruptedException → 任务提前退出 → 状态变为 INTERRUPTED → done() 执行
- 若任务是纯计算循环(无中断检查),cancel(true) 仅设中断标志,循环继续跑完 → 任务仍以 NORMAL 结束 → done() 执行但 isCancelled() 为 false
常见误区与注意事项
done() 是回调,不是同步阻塞点,不能用于等待结果或修改返回值。它内部不能调用 get(),否则可能死锁(因为 get() 会等待任务完成,而 done() 正是在完成那一刻回调)。
- 不要在 done() 中做耗时操作(如发 HTTP 请求、写磁盘),避免阻塞线程池工作线程
- done() 不保证在哪个线程执行 —— 它由执行任务的线程(或中断处理线程)调用,不是主线程专属
- 若需统一处理取消逻辑(如释放资源),应在 done() 中结合 isCancelled() 判断,而不是依赖 try-catch 或轮询
- 注意:done() 不会因 cancel(false) 失败而调用;也不会在任务被拒绝(RejectedExecutionException)时调用 —— 那属于 Executor 层面的问题,FutureTask 本身未启动
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











