java - 什么是 "incompletely constructed object"?

标签 java concurrency this publishing

Goetz 的 Java Concurrency in Practice ,第 41 页,提到 this 引用如何在构造过程中转义。一个“不要这样做”的例子:

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

这里 this 通过 doSomething(e) 引用封闭的 ThisEscape 实例这一事实“转义”。这种情况可以通过使用静态工厂方法(首先构造普通对象,然后注册监听器)而不是公共(public)构造函数(完成所有工作)来解决。本书继续:

Publishing an object from within its constructor can publish an incompletely constructed object. This is true even if the publication is the last statement in the constructor. If the this reference escapes during construction, the object is considered not properly constructed.

我不太明白。如果发布是构造函数中的最后一条语句,那么在此之前不是所有的构造工作都完成了吗?那个时候this怎么会失效呢?显然在那之后发生了一些巫术,但是什么?

最佳答案

相对于 final 字段,构造函数的末尾在并发方面是一个特殊的地方。来自 section 17.5 Java 语言规范:

An object is considered to be completely initialized when its constructor finishes. A thread that can only see a reference to an object after that object has been completely initialized is guaranteed to see the correctly initialized values for that object's final fields.

The usage model for final fields is a simple one. Set the final fields for an object in that object's constructor. Do not write a reference to the object being constructed in a place where another thread can see it before the object's constructor is finished. If this is followed, then when the object is seen by another thread, that thread will always see the correctly constructed version of that object's final fields. It will also see versions of any object or array referenced by those final fields that are at least as up-to-date as the final fields are.

换句话说,如果在另一个线程中检查对象,您的监听器最终可能会看到具有默认值的最终字段。如果在构造函数完成后发生监听器注册,则不会发生这种情况。

就正在发生的事情而言,我怀疑在构造函数的最后有一个隐式内存屏障,确保所有线程“看到”新数据;如果没有应用内存屏障,可能会出现问题。

关于java - 什么是 "incompletely constructed object"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2513597/

相关文章:

c++ - 当可以使用RVO时,为什么要按shared_ptr而不是按值返回?

javascript - jQuery - 检查这个元素是哪个?

java - 我如何在 NIO.2 中实现多播客户端?

java - JPA/Hibernate 将动态列映射为对象列表

python - python中大数据文件的并发i/o和处理

javascript - 如何使用 "this"更改 javascript 中的图像源?

javascript - Angular2 子组件在 ngFor 中意外销毁

java - 通过 XML 创建的 UI 对象不会在 Android Marshmallow 中被清除

java - 隐藏由 java 应用程序启动的窗口应用程序?

java - SwingWorker要更新TreeModel吗?