安全发布可变对象 [英] safe publication of mutable object

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

问题描述

我阅读了几个相关的问题,但是没有一个问题可以解释如何安全地发布持有人.我仍然对Java Concurrency in Practice第3.5节中的示例感到困惑:

I read several related questions, but none of them explains ways of safe publication of the Holder. I am still confused about example from Java Concurrency in Practice, section 3.5:

有一个类Holder:

There is the class Holder:

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

及其不安全的出版物:

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

可能会引发AssertionError,我同意.作者写道这是因为出版不安全,但另一方面却没有答案: 什么是正确的发布方式? 他们指出了4种安全的发布习惯用法,但我不明白,为什么它们在上述情况下会起作用:

The AssertionError could be thrown and I agree. The authors write that it is because of unsafe publication, but on the other hand there is no answer: what would be the proper way of publication? They indicates 4 safe publication idioms, but I do not understand, why would they work in the above case:

要安全地发布对象,请同时引用该对象和 对象的状态必须同时对其他线程可见. 正确构造的对象可以通过以下方式安全发布:

To publish an object safely, both the reference to the object and the object's state must be made visible to other threads at the same time. A properly constructed object can be safely published by:

  1. 从静态初始化器初始化对象引用;
  2. 将对它的引用存储到volatile字段或AtomicReference中;
  3. 将对它的引用存储到正确构造的对象的最终字段中;
  4. 或将对其的引用存储到受以下方面适当保护的字段中: 锁.
  1. Initializing an object reference from a static initializer;
  2. Storing a reference to it into a volatile field or AtomicReference;
  3. Storing a reference to it into a final field of a properly constructed object;
  4. or Storing a reference to it into a field that is properly guarded by a lock.

我同意1& 4,但对为什么以下出版物会起作用表示怀疑:

I agree with 1&4, but have doubts why following publications would work:

//safe publication
public volatile Holder holder;

//safe publication
public final Holder holder;

易失性& final仅对引用有影响,对引用的对象状态没有影响,所以我认为AssertionError仍然可能,对吧?

volatile & final have impact only for the reference, not for the referenced object state, so I think the AssertionError would be still possible, right?

作者通过代替以下方式来完善出版物,展示了如何使Holder免受不安全出版物的侵害:

Instead of publication refinement, Authors show how to make the Holder immune for the unsafe publication, by:

private final int n;

我很好奇下面的方法是否还能起作用?它与(有效)不变性有什么联系?

I am curious if the following would also work? How is it connected with (effective) immutability?

private volatile int n;

这是我在这里的第一个问题,谢谢您的帮助!

It is my first question here, thank you for your help!

推荐答案

实际上,我认为volatile是最简单的解释方法. Un 安全发布是指可以对操作进行重新排序并且不稳定的行为会阻止这种情况的发生.我可能会解释得更多,但是它已经已经解释得更多了比我要精确的.

Actually I think that volatile is the simplest to explain here. Unsafe publication happens when operations can be reordered and volatile prevents that. I could explain more probably, but it's already explained far more accurate than I will do.

基本上在下面会插入适当的内存屏障,以防止重新排序,如

Basically underneath there will be proper memory barriers inserted that will prevent re-orderings, as explained here. Essentially, what volatile does, is that if a ThreadA reads a volatile update performed by ThreadB, it is guaranteed to also see all the updates that were done before that volatile write.

final也使事情变得安全,特别是

final makes things safe too and it's specifically written in the JLS.

但是根据以下情况有两种情况:将对其的引用存储到正确构造的对象的最终字段中.

But there are two cases here according to : Storing a reference to it into a final field of a properly constructed object.

因此,根据JLS,这是安全的出版物:

So according to the JLS, this is safe publication:

class Holder {
    private final int n; // making final here
}

btw中插入了适当的内存屏障,以防止在构造引用本身时对构造函数中的存储进行重新排序.

There are proper memory barriers inserted btw that prevent stores in the constructor to be re-ordered with publishing the reference itself.

这个例子怎么样?

static class Holder {

   private int n;

   public void setN(int n){
      this.n = n;
   }
}

还有其他地方:

 class Other {
    final Holder holder;
    Other(){
        holder = new Holder();
        holder.setN(12);
    }
 }

根据

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

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