【问题标题】:coding a proof for potential concurrency issue为潜在的并发问题编写证明
【发布时间】:2013-07-19 01:15:22
【问题描述】:

我正在阅读“Java Concurrency in Practice”并尝试编写一段代码,以表明第 3.5.1 章中作为示例介绍的类确实会引入问题。

public class Holder {
    public int n;

    public Holder(int n) {
        this.n = n;
    }

    public void assertSanity() {
        if (n != n) {
            throw new AssertionError("sanity check failed!!");
        }
    }
}

那里说如果按照下面的方式使用(我相信是因为该字段是公共的,可能会出现并发问题。

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

所以我想出了这段代码,看看有没有什么不好的事情发生。

public class SanityCheck {

    public Holder holder;

    public static void main(String[] args) {

        SanityCheck sanityCheck = new SanityCheck();
        sanityCheck.runTest();

    }

    public void runTest() {
        for (int i = 0; i < 100; i++) {
            new Thread() {
                @Override
                public void run() {
                    while (true) {
                        if (holder != null) {
                            holder.assertSanity();
                        }

                        try {
                            Thread.sleep(1);
                        } catch (InterruptedException e) {
                        }
                    }
                }
            }.start();
        }

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
        }

        initialize();

    }

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

但是没有任何不好的事情发生,没有抛出 AssertionError。

能否请您帮我弄清楚为什么这段代码不会阻止任何事情?

提前感谢您抽出宝贵时间。

【问题讨论】:

    标签: java multithreading concurrency


    【解决方案1】:

    代码不是线程安全的并且可能造成并发问题的事实并不意味着它这样做。

    Java 内存模型 (JMM) 说明了程序在正确同步时必须的行为方式。但它并没有说明一个程序在不正常的情况下会如何表现。

    例如,强制执行顺序一致性的 JVM 将与 JMM 兼容,并且不会发生并发问题。

    W.r.t.您的具体示例,它不太可能在 x86/hostpot 组合上中断。

    【讨论】:

    • 我同意,在旧的多核 ARM 处理器上试一试,它可能会损坏。
    【解决方案2】:

    那里说如果用休闲方式(我相信是因为该字段是公共的,可能会出现并发问题。

    可能会出现问题,但不保证一定会出现问题。

    如果您使用的是 Oracle JVM,AFAIK 会将互操作的代码访问视为易失性。只有在您编译了构造函数和检查器后,您才会发现问题。即使那样,我怀疑你也会有困难。

    【讨论】:

      【解决方案3】:

      您不应该更改n 的值以导致某些东西中断吗?在目前的形式下,我看不出AssertionError 将如何被抛出,无论并发问题如何。

      我希望是这样的:

      if (holder != null) {
          holder.n = holder.n - 1;
          holder.assertSanity();
      }
      

      【讨论】:

      • 理论上,即使不修改 Holder.n,代码也可能会失败,因为在完整初始化可见之前,完整性检查线程可以看到 holder 的部分初始化版本,其中 n 为零.并且使用给定的代码,不能保证辅助线程将/永远/看到主线程中所做的更改,更不用说处于一致状态!
      猜你喜欢
      • 1970-01-01
      • 2010-10-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-10-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多