在Java中,对象初始化是原子操作吗?

huangapple go评论85阅读模式
英文:

Is object initialization atomic in Java?

问题

以下是翻译好的部分:

我知道 myObject1 = myObject2 是原子的,但以下代码行是否是原子的?

Object obj1 = new Object();

它是否真的可以在初始化引用的过程中被挂起?

英文:

I know myObject1 = myObject2 is atomic, but is following line of code atomic?

Object obj1 = new Object();

Can it actually be suspended in the middle of initializing a reference?

答案1

得分: 4

这不是原子操作。没有任何阻止你在对象构造函数内部添加sleep,或者无限循环,或者在构造函数内抛出异常。

**注意:**虽然可能,但这些都是反模式,不建议使用。

英文:

It is not atomic. There's nothing stopping you from putting a sleep inside the Object constructor, or an infinite loop, or throwing an exception inside the constructor.

NOTE: Although possible, these are all anti-patterns and are not recommended.

答案2

得分: 3

这行不是原子的。发生了两件事:首先创建了一个新的 Object(一般情况下不是原子的),然后将这个对象的引用赋给变量 obj1。假设这行由 Thread1 执行,而 Thread2 在随机时刻观察变量的状态。有三种状态 Thread2 可能观察到(为简单起见,假设对象创建本身是原子的):

  1. obj1 == null,对象尚未创建
  2. obj1 == null,对象已创建,但尚未将引用分配给变量
  3. obj1 != null,该行已完全执行

原子性将表明 Thread2 只能观察到状态1和3,但必须加以强制执行。使其具备原子性的一种方式是使用同步(在此示例中,obj1 是一个类字段):

public synchronized Object getObj() {
    if (obj1 == null)
        obj1 = new Object();

    return obj1;
}

调用此方法的第一个线程将初始化字段,而后续调用将简单地返回该变量。由于互斥性,在对象创建后,线程不可能观察到 obj1 中的 null,因为不同线程的方法调用不会重叠。

英文:

This line is not atomic. Two things happen: first, new Object is created (which is in general is not atomic), and then the reference to this object is assigned to the variable obj1. Say, the line executed by Thread1, and Thread2 observes the state of the variable at a random moment. There are three states Thread2 can observe (for simplicity assume object creation itself is atomic),

  1. obj1 == null, the object is not created
  2. obj1 == null, the object is created, but the reference to it is yet to be assigned to the variable
  3. obj1 != null, the line is fully executed

Atomicity would suggest that Thread2 may observe only state 1 and 3, but it has to be enforced. One way to make it atomic is via synchronization (in this example obj1 is a class field):

public synchronized Object getObj() {
    if (obj1 == null)
        obj1 = new Object();

    return obj1;
}

First thread calling this method will initialize the field, and further calls will simply return the variable. Due to mutual exclusion, it is not possible for a thread to observe null in obj1 after the object is created, since method calls by different threads cannot overlap.

答案3

得分: 2

参考赋值是原子的。没有条件会使引用本身部分赋值(这显然会导致虚拟机有时崩溃)。它要么是 null,要么不是 null。在引用分配之前的对象 构建 不是原子的,但在构建过程完成之前,您将无法访问新对象以分配给引用。

有趣的是,引用分配可以发生在芯片上的缓存内存中,这与主内存不同步。这意味着其他线程不会立即看到分配。有两种方法可以确保引用分配被推送到主内存,以便其他线程可以立即看到它:(1)将引用声明为 volatile,和(2)将引用分配放入同步块中(退出同步块将缓存的引用提交到主内存)。

英文:

The reference assignment is atomic. There is no condition under which the reference itself will be partly assigned (this would obviously cause the VM to crash at times). It will either be null or not-null. The construction of the object before the reference is assigned isn't atomic, but you won't get access to the new object to assign to the reference until the construction process is finished.

Interestingly, the reference assignment can occur in cached memory on the chip that isn't synchronized with main memory. This means other threads won't see the assignment right away. There are two ways to ensure that the reference assignment is pushed through to main memory where other threads can immediately see it. (1) declare the reference as volatile and (2) put the reference assignment in a synchronized block (exiting the synchronized block will commit the cached reference to main memory)

huangapple
  • 本文由 发表于 2020年8月9日 23:39:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/63328251.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定