Java中的可见性最终确定

时间:2014-04-15 13:47:29

标签: java android

鉴于以下实施

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,行为会改变吗?

我试图追踪JLSJSR-133The JSR-133 Cookbook for Compiler Writers,但无法真正消化规范的文字,也无法找到关于该问题的明确文章。

此外,这是'JSR-133 Cookbook for Compiler Writers'所说的:

  

终结支持可能需要障碍(垃圾收集器中的 )   确保Object.finalize代码将所有商店都看到所有字段   在对象变得未被引用之前。通常可以确保这一点   通过同步来添加和删除引用中的引用   队列。

4 个答案:

答案 0 :(得分:1)

Foo在堆栈上实例化,这是一个对象,它将在堆上,引用将在堆栈上。

您确实意识到最终确定可能根本不会被调用

答案 1 :(得分:1)

根据JLS 17.4.5

  

“从对象的构造函数结尾到该对象的终结符(第12.6节)的开头有一个发生前的边缘。”

但是,如果在构造对象后调用close(),则会在其间写入closed字段。为了保证终结器线程能够看到更新的值,closed必须是易失性的,或者必须在互斥(或等效)下访问和更新...以便添加必要的“发生的” -before”。

答案 2 :(得分:0)

是的,closed需要声明为volatile,以确保价值更改可见性。另请注意,无法保证finalize()将被呼叫,因此依赖其电话是不好的做法。

答案 3 :(得分:0)

如果在初始化之后可以更改字段,则应同步该字段以使该类具有线程安全性。由于finalize()将从与close()方法不同的线程调用,因此它可能会看到过时的接近值