安全发布可变对象

88m*_*usz 6 java multithreading immutability

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

有班主持人:

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.");
    }
}
Run Code Online (Sandbox Code Playgroud)

及其不安全的出版物:

//unsafe publication
public Holder holder;
    public void initialize() {
        holder = new Holder(42);
    }
Run Code Online (Sandbox Code Playgroud)

可能会抛出AssertionError,我同意.作者写道,这是因为不安全的出版物,但另一方面没有答案: 什么是正确的出版方式? 它们表示4种安全的出版习语,但我不明白,为什么它们会在上述情况下起作用:

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

  1. 从静态初始化程序初始化对象引用;
  2. 将对它的引用存储到volatile字段或AtomicReference中;
  3. 将对它的引用存储到正确构造的对象的最终字段中;
  4. 或者将对它的引用存储到一个被锁适当保护的字段中.

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

//safe publication
public volatile Holder holder;
Run Code Online (Sandbox Code Playgroud)

要么

//safe publication
public final Holder holder;
Run Code Online (Sandbox Code Playgroud)

volatile和final只对引用有影响,而不是对引用的对象状态有影响,所以我认为AssertionError仍然可能,对吧?

作者没有对出版物进行改进,而是通过以下方式展示如何使Holder免受不安全出版物的影响:

private final int n;
Run Code Online (Sandbox Code Playgroud)

我很好奇以下是否也能奏效?它与(有效)不变性有何关联?

private volatile int n;
Run Code Online (Sandbox Code Playgroud)

这是我的第一个问题,谢谢你的帮助!

Joe*_*Joe 0

使整数易失性并将其与您同意的线程同步到锁定对象。

这不是确切的代码,而是一个供您理解的想法。没有两件事可以同时作用于一件事。这就是导致程序甚至操作系统死锁的原因。

第1类:

public static final Object lock = new Object();
private Holder holder;
public abstract void method1(); //Assume these two go to different places
public abstract void method2(); //At different times w/ different implementations
Run Code Online (Sandbox Code Playgroud)

主题1:

public void method1() {
    synchronized(Class1.lock) {
        holder.assertMadness();
    }
}
Run Code Online (Sandbox Code Playgroud)

话题2:

public void method2() {
    synchronized(Class1.lock) {
        holder.assertMadness();
    }
}
Run Code Online (Sandbox Code Playgroud)