为什么JMM会产生(0, 0)的结果,尽管它被认为是一个禁止的结果。

huangapple go评论144阅读模式
英文:

Why JMM produces (0, 0) even though it is considered a forbidden result

问题

我正在检查一些来自JMMJava内存模型的语句并且我编写了一个类似这样的JCSJava Concurrency Stress测试

    @JCStressTest
    @State
    @Outcome(expect = ACCEPTABLE, desc = "ACCEPTABLE")
    public class ConcurrencyTest {
        private final int a = 1;
        private final int b = 2;
    
        public ConcurrencyTest instance;
        
        @Actor
        public void actor1() {
            instance = new ConcurrencyTest();
        }
    
        @Actor
        public void actor2(II_Result result) {
            ConcurrencyTest c = instance;
            if (c != null) {
                result.r1 = c.a;
                result.r2 = c.b;
            }
        }
    }

在运行了这个测试之后我看到了以下结果

> (0, 0) (1, 2)

尽管JMM明确指出结果(0, 0)是不允许的但是为什么会发生这种情况呢
英文:

I am checking some statements from JMM and I wrote a JCS test like this:

@JCStressTest
@State
@Outcome(expect = ACCEPTABLE,  desc = "ACCEPTABLE")
public class ConcurrencyTest {
    private final int a = 1;
    private final int b = 2;

    public ConcurrencyTest instance;
    
    @Actor
    public void actor1() {
        instance = new ConcurrencyTest();
    }

    @Actor
    public void actor2(II_Result result) {
        ConcurrencyTest c = instance;
        if (c != null) {
            result.r1 = c.a;
            result.r2 = c.b;
        }
    }
}

After running this test, I see the following results:

> (0, 0) (1, 2)

Although the JMM explicitly states that the result (0, 0) is forbidden, why is this happening?

答案1

得分: 2

让我们首先稍微修改一下代码:

@JCStressTest
@State
@Outcome(id = "0, 0", expect = Expect.FORBIDDEN)
@Outcome(id = "1, 2", expect = Expect.ACCEPTABLE)
@Outcome(id = "-1, -1", expect = Expect.ACCEPTABLE)
public class ConcurrencyTest {

    private final int a = 1;
    private final int b = 2;

    public ConcurrencyTest instance;

    @Actor
    public void actor1() {
        instance = new ConcurrencyTest();
    }

    @Actor
    public void actor2(II_Result result) {
        ConcurrencyTest c = instance;
        if (c != null) {
            result.r1 = c.a;
            result.r2 = c.b;
        } else {                   // <-- 这是你需要关注的部分
            result.r1 = -1;
            result.r2 = -1;
        }
    }
}

你认为@Outcome(id = "0, 0")中的值是从哪里来的?这些值是你在II_Result中设置的,它保存了两个int值,默认值为0

因此,当c == null(表示actor1尚未运行)时,if (c != null) { ... }将不会被执行。所以,在你的代码中,你不会做任何操作:导致r1r2的默认值为零。你应该通过一个简单的else来处理这种默认情况,就像我做的一样。

英文:

Let's change the code a little bit to begin with:

@JCStressTest
@State
@Outcome(id = &quot;0, 0&quot;, expect = Expect.FORBIDDEN)
@Outcome(id = &quot;1, 2&quot;, expect = Expect.ACCEPTABLE)
@Outcome(id = &quot;-1, -1&quot;, expect = Expect.ACCEPTABLE)
public class ConcurrencyTest {

    private final int a = 1;
    private final int b = 2;

    public ConcurrencyTest instance;

    @Actor
    public void actor1() {
        instance = new ConcurrencyTest();
    }

    @Actor
    public void actor2(II_Result result) {
        ConcurrencyTest c = instance;
        if (c != null) {
            result.r1 = c.a;
            result.r2 = c.b;
        } else {                   // &lt;-- this is what you care about
            result.r1 = -1;
            result.r2 = -1;
        }
    }
}

Where do you think that the values from @Outcome(id = &quot;0, 0&quot;) are coming from? These are the ones you set in II_Result that holds two ints, that have a default value of 0.

As such, when c == null (meaning that actor1 has not run), that if (c != null) { ... will not be entered. So, in your code, you would do nothing : resulting in those default values of r1 and r2 being zero. You should take care of this default cases, via a simple else, like I did.

huangapple
  • 本文由 发表于 2020年7月23日 17:08:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/63050742.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定