Java对象引用的不当发布 [英] Improper publication of Java Object Reference

查看:106
本文介绍了Java对象引用的不当发布的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下示例来自Brian Goetz的书Java Concurrency in Practice,第3章,第3.5.1节。这是一个错误发布对象的示例

The below example is from the book "Java Concurrency in Practice" by Brian Goetz, Chapte 3, Section 3.5.1. This is an example of Improper publication of objects

class someClass {
    public Holder holder;

    public void initialize() {
        holder = new Holder(42);
    }
}

public class Holder {
  private int n;
  public Holder(int n) { this.n = n; }

  public void assertSanity() {
    if (n!=n)
      throw new AssertionError("This statement is false");
  }
}

它说明持有者可能出现在另一个线程处于不一致状态,另一个线程可以观察到部分构造的对象。这怎么会发生?你可以使用上面的例子给出一个场景吗?

It says that the the Holder could appear to another thread in a inconsistent state and another thread could observer a partially constructed object. How can this happen? Could you give a scenario using the above example?

也可以说,有一种情况下,线程可能在第一次读取字段时看到一个陈旧的值然后下一次更新的值,这就是为什么assertSanity可以抛出Assertion Error。如何抛出assertionError?

Also it goes on to say that there are cases when a thread may see a stale value the first time it reads a field and then a more upto date value the next time, which is why the assertSanity can throw Assertion Error. How can the assertionError be thrown?

从另一个角度来看,解决这个问题的方法之一是通过使变量'n'最终使得Holder不可变。现在,让我们假设持有者不是不可变的,而是有效地不变的。为了安全地发布这个对象,我们必须让holder初始化为static,并声明为volatile(静态初始化和volatile或者volatile)。类似

From futher reading, one way to fix this problem is to make Holder immutable by making the variable 'n' final. For now, let us assume that Holder is not immuntable but effectively immutable. To safely publish this object, do we have to make holder initialization static and declare it as volatile( both static intialization and volatile or just volatile)? Something like

public class someClass {
    public static volatile Holder holder = new Holder(42);

}

感谢您的帮助。

推荐答案

你可以想象一个对象的创建有一些非原子的函数。首先,您要初始化和发布持有人。但是你还需要初始化所有的私有成员字段并发布它们。

You can imagine creation of an object has a number of non-atomic functions. First you want to initialize and publish Holder. But you also need to initialize all the private member fields and publish them.

JMM没有写入和发布持有者的规则初始化()之前写入持有 $ c>。这意味着即使 holder 不为null,成员字段对其他线程仍不可见,这是合法的。

Well the JMM has no rules for the write and publication of the holder's member fields to happen-before the write of the holder field as occurring in initialie(). What that means is that even though holder is not null it is legal for the member fields to not yet be visible to other threads.

您可能最终看到类似

public class Holder{
    String someString = "foo";
    int someInt = 10;
} 

为null,但是 someString 可以为null, someInt 可以为0。

holder may not be null but someString could be null and someInt could be 0.

在x86拱下,这是,从我知道,不可能发生,但可能不是在其他人的情况。

Under an x86 arch this is, from what I know, impossible to happen but may not be the case in others.

所以下一个问题可能是为什么volatile修复这个问题? JMM说,在volatile存储之前发生的所有写操作对volatile字段的所有后续线程都可见。

So next question may be Why does volatile fix this? The JMM says that all writes that happen prior to the volatile store are visible to all subsequent threads of the volatile field.

因此,如果 holder 是volatile并且您看到 holder 不为null,所有字段都将被初始化。

So if holder is volatile and you see holder is not null, based on volatile rules, all of the fields would be initialized.


为了安全地发布此对象,我们必须使
初始化静态和声明它作为volatile

To safely publish this object, do we have to make holder initialization static and declare it as volatile

是的,因为我提到如果 holder

Yes, because as I mentioned if the holder variable is not null then all writes would be visible.

如果线程发现 holder 不为null,并调用 assertionError 在输入方法并读取 n 时,第一次可以是 0 (默认值),第二次读取 n 现在可以看到来自第一个线程的写入。

If a thread notices holder not to be null, and invokes assertionError upon entering the method and reading n the first time may be 0 (the default value), the second read of n may now see the write from the first thread.

这篇关于Java对象引用的不当发布的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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