引擎盖下的Java类构造

voi*_*ipp 1 java concurrency thread-safety

考虑我们有这样的类:

class A {
    public B b;

    public void someFunc() { // called sometime
        b = new B();
    }
}
Run Code Online (Sandbox Code Playgroud)

B的构造函数分配一些内部变量。

现场b是不是线程安全的在这个意义上另一个线程可以查看b不可─ nullB构造尚未完成。(someFunc执行期间)

我的问题是:从逻辑角度看,构造函数还没有完成怎么办?

对我来说,这种重新排序是不可思议的。

Rad*_*def 5

在线程安全的上下文中,这通常是由于即时(JIT)编译器引起的。JIT编译器采用Java字节码并将其转换为机器码,以使其运行更快。在翻译过程中,它可以进行很多优化,例如内联各种方法和构造函数。

假设B有一个这样的构造函数:

class B {
    int x;
    B(int x) { this.x = x; }
}
Run Code Online (Sandbox Code Playgroud)

内联构造函数时,它将使用类似于以下内容的Java代码:

b = new B(1);
Run Code Online (Sandbox Code Playgroud)

并将其转换为采用类似于以下步骤的机器代码:

  1. B以某种方式为对象分配空间。
  2. 将指向该内存的指针存储在中b
  3. 存放1b.x

换句话说,与此类似的代码(在排序方面):

b = new B();
b.x = 1;
Run Code Online (Sandbox Code Playgroud)

但是我们实际上根本不调用构造函数。我们只分配一个B,但是JVM在内部进行分配,然后b.x直接分配。调用构造函数将涉及跳转指令,因此内联它要快一些。

著名的“双重检查锁定已损坏”声明中有一个例子。

常规Java编译器也可以内联构造函数,但是常规Java编译器通常不执行许多优化。