为什么 JMM 产生 (0, 0) 即使它被认为是禁止的结果

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

我正在检查 JMM 的一些语句,并且我编写了一个 JCS 测试,如下所示:

@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) 是禁止的,但为什么会这样?

让我们稍微更改一下代码:

@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 {                   // <-- this is what you care about
            result.r1 = -1;
            result.r2 = -1;
        }
    }
}

您认为 @Outcome(id = "0, 0") 中的值来自哪里?这些是您在 II_Result 中设置的,其中包含两个 int,默认值为 0

这样,当c == null(意思是actor1没有运行)时,if (c != null) { ... 将不会被输入。因此,在您的代码中,您什么都不做:导致 r1r2 的默认值为零。您应该像我一样通过简单的 else 来处理这种默认情况。