在构建过程中,Java对象何时变为非null? [英] When does a java object become non-null during construction?

查看:106
本文介绍了在构建过程中,Java对象何时变为非null?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设您正在创建如下的java对象:

Say you are creating a java object like so:

SomeClass someObject = null;
someObject = new SomeClass();

someObject何时变为非null?是 SomeClass()构造函数运行之前还是之后?

At what point does the someObject become non-null? Is it before the SomeClass() constructor runs or after?

要澄清一点,说如果另一个线程要检查 someObject 是否为null,而 SomeClass()构造函数在完成中途时, null

To clarify a little, say if another thread was to check if someObject was null while the SomeClass() constructor was halfway through completion, would it be null or non-null?

另外,如果 someObject 创建时会有什么区别:

Also, what would be the difference if someObject was created like so:

SomeClass someObject = new SomeClass();

会将 someObject p>

Would someObject ever be null?

推荐答案

如果另一个线程在构建期间检查 someObject 我相信这可能(由于内存模型中的怪癖)看到一个部分初始化的对象。新的(从Java 5开始)内存模型意味着任何 final 字段应该在对象变为其他线程可见之前设置为它们的值(只要对新创建的对象的引用不会

If another thread were to check the someObject variable "during" construction, I believe it may (due to quirks in the memory model) see a partially initialized object. The new (as of Java 5) memory model means that any final fields should be set to their values before the object becomes visible to other threads (so long as the reference to the newly created object doesn't escape from the constructor in any other way) but beyond that there aren't many guarantees.

基本上,不要共享数据没有适当的锁定(或由静态赋值的保证) inializers等):)认真地,内存模型是严重棘手,一般是无锁编程。

Basically, don't share data without appropriate locking (or guarantees given by static inializers etc) :) Seriously, memory models are seriously tricky, as is lock-free programming in general. Try to avoid this becoming a possibility.

逻辑术语中,分配会在构造函数运行后发生您观察到来自同一个线程的变量 ,它在构造函数调用期间将为null。

In logical terms the assignment happens after the constructor runs - so if you observe the variable from the same thread it will be null during the constructor call. However, as I say there are memory model oddities.

编辑:为了双重检查锁定,你可以使用这个 if 您的字段为 volatile 如果您使用的是Java 5或更高版本。在Java 5之前,内存模型不够强大。你需要正确获得模式 。参见Effective Java,第2版,第71项,了解更多细节。

For the purposes of double-checked locking, you can get away with this if your field is volatile and if you're using Java 5 or higher. Prior to Java 5 the memory model wasn't strong enough for this. You need to get the pattern exactly right though. See Effective Java, 2nd edition, item 71 for more details.

编辑:这里是我的论据,反对Aaron的内联在单线程中可见。假设我们有:

Here's my reasoning for arguing against Aaron's inlining being visible in a single thread. Suppose we have:

public class FooHolder
{
    public static Foo f = null;

    public static void main(String[] args)
    {
        f = new Foo();
        System.out.println(f.fWasNull);
    }
}

// Make this nested if you like, I don't believe it affects the reasoning
public class Foo
{
    public boolean fWasNull;

    public Foo()
    {
        fWasNull = FooHolder.f == null;
    }
}

我相信这总会< > report true 。从第15.26.1 节:


否则,需要三个步骤:

Otherwise, three steps are required:


  • 首先,对左手操作数求值以产生一个变量。如果此评估突然完成
    ,则赋值
    表达式突然完成
    同样的原因;右侧的操作数是
    未评估,并且没有赋值

  • 否则,右侧的操作数被求值。如果
    评估突然完成,则
    分配表达式由于相同的原因突然完成
    ,并且不发生
    分配。

    • First, the left-hand operand is evaluated to produce a variable. If this evaluation completes abruptly, then the assignment expression completes abruptly for the same reason; the right-hand operand is not evaluated and no assignment occurs.
    • Otherwise, the right-hand operand is evaluated. If this evaluation completes abruptly, then the assignment expression completes abruptly for the same reason and no assignment occurs.

      然后从第17.4.5节

      两动作可以通过发生 - 之前的关系来排序。如果一个动作发生在另一个动作之前,那么第一个动作在第二个动作之前可见和排序。

      Two actions can be ordered by a happens-before relationship. If one action happens-before another, then the first is visible to and ordered before the second.


      如果我们有两个动作x和y ,我们写hb(x,y)来表示x发生在y之前。

      If we have two actions x and y, we write hb(x, y) to indicate that x happens-before y.


      • 如果x和y是同一个线程的动作x在程序顺序中位于y之前,然后是hb(x,y)。

      • 从对象的构造函数末尾到终结器(§12.6)。

      • 如果操作x与下面的操作y同步,那么我们也有hb(x,y)。

      • 如果hb(x,y)和hb(y,z),则hb(x,z)。

      • If x and y are actions of the same thread and x comes before y in program order, then hb(x, y).
      • There is a happens-before edge from the end of a constructor of an object to the start of a finalizer (§12.6) for that object.
      • If an action x synchronizes-with a following action y, then we also have hb(x, y).
      • If hb(x, y) and hb(y, z), then hb(x, z).

      应该注意的是,两个
      操作之间存在一个happens-before关系并不一定意味着在
      实现中以该顺序发生。如果重新排序产生的结果与法律执行相符,
      这不是非法的。

      It should be noted that the presence of a happens-before relationship between two actions does not necessarily imply that they have to take place in that order in an implementation. If the reordering produces results consistent with a legal execution, it is not illegal.

      换句话说,奇怪的东西发生,即使在单个线程,但不能是可观察的。在这种情况下,差异是可观察的,这就是为什么我相信这是非法的。

      In other words, it's okay for weird stuff to happen even within a single thread but that mustn't be observable. In this case the difference would be observable, which is why I believe it would be illegal.

      这篇关于在构建过程中,Java对象何时变为非null?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆