Java内存模型中的部分构造的对象

MC *_*ror 3 java concurrency final java-memory-model

在Internet上某处的文章中遇到了以下代码:

public class MyInt {

    private int x;

    public MyInt(int y) {
        this.x = y;
    }

    public int getValue() {
        return this.x;
    }
}
Run Code Online (Sandbox Code Playgroud)

文章指出

编译器(JIT,CPU等)不对构造器进行特殊处理,因此允许对构造器中的指令和构造器之后的指令进行重新排序。

另外,关于Java内存模型的这篇JSR-133文章指出:

保证只有在对象完全初始化之后才能看到对对象的引用的线程才能确保看到该对象的最终字段的正确初始化值。

上面提到的MyInt实例似乎是不可变的(除了未标记该类的情况final)并且是线程安全的,但文章指出并非如此。他们声明不能保证x读取时始终具有正确的值。

但是我认为

在创建对象时,只有创建对象的线程才可以访问它

Java教程都显得很支持。

我的问题是:这是否意味着在当前的JMM中,由于指令重新排序,线程可以访问部分构造的对象?如果是的话,怎么办?这是否意味着Java教程中的陈述是不正确的?

Daw*_*ica 5

那篇文章说,如果您有类似的代码

foo = new MyInt(7);
Run Code Online (Sandbox Code Playgroud)

在有一个领域的课上

MyInt foo;
Run Code Online (Sandbox Code Playgroud)

那么说明就是

(reference to new object).x = 7;
foo = (reference to new object);
Run Code Online (Sandbox Code Playgroud)

可以交换为某种优化。这将永远不会改变正在运行此代码的线程的行为,但是有可能其他一些线程将foo在行之后读取

foo = (reference to new object);
Run Code Online (Sandbox Code Playgroud)

但在行前

(reference to new object).x = 7;
Run Code Online (Sandbox Code Playgroud)

在这种情况下,它会显示foo.x0,而不是7。也就是说,其他线程可以运行

int bar = someObject.getFoo().getValue();
Run Code Online (Sandbox Code Playgroud)

并最终bar等于0

我从来没有见过这样的事情在野外发生,但是作者似乎知道他在说什么。