在 JavaOne 2026 临近之际,OpenJDK 通过 Quality Outreach(版本质量共建计划)向社区发出了一条重要提醒:
JDK 27 将移除 ThreadPoolExecutor.finalize() 方法。
这看似只是删除一个“空实现”,但它背后代表着 Java 平台持续多年的一个大方向:
彻底淘汰 finalization 机制。
对于部分老项目来说,这次改动甚至可能带来 直接的编译错误。如果你计划升级到未来的 JDK 版本,这件事值得提前关注。
finalize 机制为何被弃用?
在早期 Java 中,如果对象在被 GC 回收前需要释放资源,常见做法是实现:
protected void finalize() throws Throwable
垃圾回收器会在对象不可达后调用这个方法,这一过程被称为 finalization。
但这个机制长期以来问题不断:
- 执行时机不可预测
- 容易写出不可靠代码
- 存在安全风险
- 会影响性能
- 会延长对象生命周期
随着 Java 7 引入 try-with-resources,后续又推出 Cleaner API[1],官方逐渐明确态度:
finalize 应该被淘汰。
时间线大致如下:
- JDK 9 起逐步减少 JDK 内部 finalize 使用
- JDK 18(JEP 421)将 finalization 标记为“将移除”
- 后续版本持续清理
- JDK 27:继续删除遗留 finalize 实现
ThreadPoolExecutor.finalize() 的演进与影响
ThreadPoolExecutor 曾经包含一个 finalize() 方法,但它已经经历了多轮弱化:
| 版本 |
状态 |
| JDK 9 |
标记为 deprecated |
| JDK 11 |
改为空实现 |
| JDK 18 |
标记为将移除 |
| JDK 27 |
正式删除 |
也就是说:
这个方法已经 什么都不做很多年。
但 JDK 27 会把它彻底移除。问题在于:
删除它仍然会影响现有代码。
原因在于 Object.finalize() 的异常签名:
protected void finalize() throws Throwable { }
而 ThreadPoolExecutor.finalize() 不抛异常:
protected void finalize() {}
过去如果你的 ThreadPoolExecutor 子类这样写:
@Override
protected void finalize() {
super.finalize();
}
或在其他地方直接调用 ThreadPoolExecutor.finalize(),编译器认为调用的是:
ThreadPoolExecutor.finalize()
不会抛异常。
但在 JDK 27 中,这个方法被删除后:
- 调用会落到
Object.finalize()
- 它声明
throws Throwable
- 编译器要求处理异常
结果就是:
旧代码可能在 JDK 27 上直接编译失败。
这就是典型的 source incompatible change(源码不兼容变更)。
影响主要集中在以下场景:
- 自定义线程池继承
ThreadPoolExecutor
- 框架内部封装线程池
- 老旧代码仍实现 finalize
- 手动调用
super.finalize()
特别是一些历史较长的企业项目或开源库,需要重点检查。
替代方案与迁移建议
OpenJDK 的建议很明确:
不要修补 finalize,应该彻底移除。
推荐替代方案:
1. try-with-resources
try (ExecutorService pool = ...) {
// use
}
2. 显式 shutdown
executor.shutdown();
3. Cleaner API
Cleaner cleaner = Cleaner.create();
cleaner.register(obj, () -> cleanup());
这些方式都比 finalize 更可预测、更安全。
如果短期内无法删除 finalize,可以使用临时方案:
@Override
protected void finalize() {
try {
super.finalize();
} catch (Throwable ignored) {
}
}
但要注意:
Object.finalize() 实际为空实现
- 只是为了编译通过
- 不应该长期保留
更清晰的 Java 演进方向
ThreadPoolExecutor.finalize() 的移除只是 Java 清理历史机制的一部分。近年来 Java 的方向非常清晰:
| 旧机制 |
新方向 |
| finalize |
try-with-resources / Cleaner |
| Thread.stop |
interrupt |
| SecurityManager |
新安全模型 |
| 隐式资源释放 |
显式生命周期管理 |
Java 正在变得:
如果你的项目未来会升级 JDK 27,建议现在就开始排查。
1. 搜索代码
finalize(
super.finalize(
2. 用 EA 版本测试
使用 JDK 27 EA 跑 CI。
3. 清理 finalize
特别是线程池相关实现。
References
[1] Cleaner API: https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/ref/Cleaner.html