英文:
Why JMM produces (0, 0) even though it is considered a forbidden result
问题
我正在检查一些来自JMM(Java内存模型)的语句,并且我编写了一个类似这样的JCS(Java 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) { ... }
将不会被执行。所以,在你的代码中,你不会做任何操作:导致r1
和r2
的默认值为零。你应该通过一个简单的else
来处理这种默认情况,就像我做的一样。
英文:
Let's change the code a little bit to begin with:
@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;
}
}
}
Where do you think that the values from @Outcome(id = "0, 0")
are coming from? These are the ones you set in II_Result
that holds two int
s, 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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论