java - 不安全发布并发java

标签 java multithreading concurrency

<分区>

Java concurrency in practice book已经给出了不安全发布的例子

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

上面的代码看起来是线程安全的。如果 n 是公共(public)变量,它就不是线程安全的。书上的例子错了吗?

最佳答案

安全发布与内存可见性有关。内存可见性的概念比竞争条件等其他线程安全问题要复杂一些。

当一个线程以特定顺序执行的操作对另一个线程似乎以不同的顺序执行时,就会出现内存可见性问题(这可能是由编译器或 CPU 进行的优化引起的)。

在你的情况下:

// Thread A
h = new Holder(42);

// Thread B
h.assertSanity();

对于线程A来说,n肯定是在h之前初始化的。

但是在没有安全发布的情况下,线程 B 不能保证它是相同的。线程 B 可能会看到 h 处于初始化状态,但 n 不会被初始化然而。此外,线程 B 观察到的 n 的状态可能会在评估 n != n 期间发生变化,从而导致 assertSanity() 抛出异常.

请注意,此问题并不能保证在所有情况下都会发生。您可能永远不会看到这种情况发生,但 Java 内存模型仍然不能保证这种情况下的正确性。

关于java - 不安全发布并发java,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18618522/

相关文章:

java - 尝试添加 Firebase UI 2.3.0 时,我不断收到 gradle 同步错误

java - 需要加速 GOval 对象的帮助(制作 Breakout 游戏)

java - 在 AsyncTask 中获取 Json 时,项目未添加到列表 <Object> 中

multithreading - Delphi (XE2) Indy (10) 多线程 Ping

java - java.net.SocketTimeoutException : Read timed out 的原因是什么

c# - 如何在多线程应用程序中安全地填充数据和 Refresh() DataGridView?

java - JProfiler 分析新线程

python - 异步 : running task only if all other tasks are awaiting

java - ExecutorService.invokeAll 和关闭

java - 并发读者-作者的行为方式出乎意料