链接构造函数时,JVM 的隐式内存屏障如何表现?

参考我的之前关于不完全构造对象的问题,我有一个第二个问题.正如 Jon Skeet 指出的那样,构造函数末尾有一个隐式内存屏障,可确保 final 字段对所有线程都是可见的.但是如果一个构造函数调用另一个构造函数呢?他们每个人的末尾是否有这样的内存屏障,或者仅在首先被调用的那个末尾?也就是说,当错误"的解决方案是:

Referring to my earlier question on incompletely constructed objects, I have a second question. As Jon Skeet pointed out, there's an implicit memory barrier in the end of a constructor that makes sure that final fields are visible to all threads. But what if a constructor calls another constructor; is there such a memory barrier in the end of each of them, or only in the end of the one that got called in the first place? That is, when the "wrong" solution is:

public class ThisEscape {
    public ThisEscape(EventSource source) {
        source.registerListener(
            new EventListener() {
                public void onEvent(Event e) {
                    doSomething(e);
                }
            });
    }
}

正确的是工厂方法版本:

And the correct one would be a factory method version:

public class SafeListener {
    private final EventListener listener;

    private SafeListener() {
        listener = new EventListener() {
            public void onEvent(Event e) {
                doSomething(e);
            }
        }
    }

    public static SafeListener newInstance(EventSource source) {
        SafeListener safe = new SafeListener();
        source.registerListener(safe.listener);
        return safe;
    }
}

以下是否也有效?

public class MyListener {
    private final EventListener listener;

    private MyListener() {
        listener = new EventListener() {
            public void onEvent(Event e) {
                doSomething(e);
            }
        }
    }

    public MyListener(EventSource source) {
        this();
        source.register(listener);
    }
}

更新: 基本问题是 this() 保证实际上 调用 上面的私有构造函数(在这种情况下会有预期的屏障并且一切都是安全的),或者私有构造函数是否有可能内联到公共构造函数中作为保存一个内存屏障的优化(在这种情况下不会有障碍直到公共构造函数结束)?

Update: The essential question is that is this() guaranteed to actually call the private constructor above (in which case there would be the barrier where intended and everything would be safe), or is it possible that the private constructor gets inlined into the public one as an optimization to save one memory barrier (in which case there wouldn't be a barrier until in the end of the public constructor)?

this() 的规则是否在某处精确定义?如果不是,那么我认为我们必须假设允许内联链式构造函数,并且可能某些 JVM 甚至 javac 正在这样做.

Are the rules of this() defined precisely somewhere? If not, then I think we must assume that inlining chained constructors is allowed, and probably some JVMs or maybe even javacs are doing it.

推荐答案

我认为这是安全的,因为 java 内存模型指出:

I think it is safe as java memory model states that:

令 o 为对象,c 为 o 的构造函数,其中一个 final字段 f 被写入.对 o 的最后一个字段 f 执行冻结操作当 c 正常或突然退出时.请注意,如果一个构造函数调用另一个构造函数,而被调用的构造函数设置一个最终字段,最终字段的冻结发生在调用的构造函数结束.

Let o be an object, and c be a constructor for o in which a final field f is written. A freeze action on final field f of o takes place when c exits, either normally or abruptly. Note that if one constructor invokes another constructor, and the invoked constructor sets a final field, the freeze for the final field takes place at the end of the invoked constructor.

相关文章