为潜在的并发问题编写证明

时间:2013-07-18 16:09:50

标签: java multithreading concurrency

我正在阅读“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。

你能帮我弄清楚为什么这段代码不会制动任何东西?

提前感谢您的时间。

3 个答案:

答案 0 :(得分:3)

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

Java内存模型(JMM)说明程序在正确同步时必须的行为方式。但它并没有说明程序

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

W.r.t。你的具体例子,它不太可能打破x86 / hostpot组合。

答案 1 :(得分:2)

  

据说,如果以下述方式使用(我认为这是关于该字段是公开的事实,可能会发生并发问题。

可能会出现问题,但无法保证会出现任何问题。

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

答案 2 :(得分:0)

你不应该改变n的值来导致某些事情破裂吗?在它的当前形式中,我不知道如何抛出AssertionError,无论并发问题如何。

我期待这样的事情:

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