鉴于以下实施
class Foo {
private RuntimeException closed = new IllegalStateException("not closed");
public void close() {
closed = null;
}
protected void finalize() {
if (closed != null)
closed.printStackTrace();
}
}
closed
是否需要定义volatile
?如果在堆栈上实例化Foo
,行为会改变吗?
我试图追踪JLS,JSR-133和The JSR-133 Cookbook for Compiler Writers,但无法真正消化规范的文字,也无法找到关于该问题的明确文章。
此外,这是'JSR-133 Cookbook for Compiler Writers'所说的:
终结支持可能需要障碍(垃圾收集器中的 ) 确保Object.finalize代码将所有商店都看到所有字段 在对象变得未被引用之前。通常可以确保这一点 通过同步来添加和删除引用中的引用 队列。
答案 0 :(得分:1)
Foo在堆栈上实例化,这是一个对象,它将在堆上,引用将在堆栈上。
您确实意识到最终确定可能根本不会被调用?
答案 1 :(得分:1)
根据JLS 17.4.5:
“从对象的构造函数结尾到该对象的终结符(第12.6节)的开头有一个发生前的边缘。”。
但是,如果在构造对象后调用close()
,则会在其间写入closed
字段。为了保证终结器线程能够看到更新的值,closed
必须是易失性的,或者必须在互斥(或等效)下访问和更新...以便添加必要的“发生的” -before”。
答案 2 :(得分:0)
是的,closed
需要声明为volatile
,以确保价值更改可见性。另请注意,无法保证finalize()
将被呼叫,因此依赖其电话是不好的做法。
答案 3 :(得分:0)
如果在初始化之后可以更改字段,则应同步该字段以使该类具有线程安全性。由于finalize()将从与close()方法不同的线程调用,因此它可能会看到过时的接近值