Java同步-不正确的发布

标签 java multithreading concurrency thread-safety

这是《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() 会抛出 AssertionError - 当“Holder”实例处于实例化过程中并且“n”的默认值尚未设置为“42”时。

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

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

还有其他情况吗?

谢谢大家!

最佳答案

由于重新排序,你无法真正思考“这发生在那之后”。例如

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

实际上可能会出现这样的情况:一个线程观察到构造函数已经退出并且对象已经初始化,但是另一个线程可能看到了引用(因此它也认为构造函数已经退出),但是对象的字段还没有已为此线程初始化。

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

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

关于Java同步-不正确的发布,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31875443/

相关文章:

java - 在 Java 中从变量声明新类

java - 为什么这个多线程计数器会产生正确的结果?

c++ - 如何确保始终有给定数量的线程? (另外,这是线程的一个很好的用法吗?)

multithreading - 测试高并发工作线程系统的正确方法是什么?

jakarta-ee - 如果有异步方法仍在运行,无状态 session 是否会被另一个线程使用?

java - 使用 JSch 的多个命令

java - 当我作为导出的 jar 运行时,出现 FileNotFoundException

java - 当表具有外键时 Telosys 代码生成失败

c++ - 如何探测 std::mutex?

java - Java中的生产者/消费者模式