有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

多线程Java同步不正确的发布

这是《实践中的Java并发》一书的摘录:

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

... Because of visibility problems, the Holder could appear to another thread to be in an inconsistent state, even though its invariants were properly established by its constructor! This improper publication could allow another thread to observe a partially constructed object. ...

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.");
    }
}

... But far worse, other threads could see an up-to-date value for the holder reference, but stale values for the state of the Holder. ...

To make things even less predictable, a thread may see a stale value the first time it reads a field and then a more up-to-date value the next time, which is why assertSanity can throw AssertionError. ... the Object constructor first writes the default values to all fields before subclass constructors run. It is therefore possible to see the default value for a field as a stale value.

我的问题:

似乎只有两种情况下assertSanity()可以抛出AssertOnError—当“Holder”实例处于实例化过程中且“n”的默认值尚未设置为“42”时

  1. Java将在构造函数退出之前(在构造函数初始化“n”字段之前),将部分创建的对象放入“holder”引用中。 另一个线程将尝试在此部分创建的对象上调用“assertSanity”。 因此,“n!=n”操作必须足够长才能发生AssertionError

  2. 当assertSanity()正在进行时,本地缓存的“holder”突然变为可见

还有其他情况吗

谢谢大家


共 (1) 个答案

  1. # 1 楼答案

    你不能真的用“这件事发生在那之后”来思考,因为重新排序。比如说

    Java will put partially created object in "holder" reference before constructor exits (before constructor initialize "n" field)

    实际上,可能会发生这样的情况:一个线程观察到构造函数已退出,对象已初始化,但另一个线程可能看到引用(因此它也认为构造函数已退出),但对象的字段尚未为此线程初始化

    因此,事情变得非常不可预测,因为如果没有适当的同步,不同的线程可能会观察到不同顺序的状态变化,或者根本看不到。这里几乎不可能对所有可能的情况进行推理:(

    我强烈建议您阅读《Java并发实践》一书中的“Java内存模型”部分