java volatile 的语义是否保证不会出现错误的结果? (两个线程先写后读)
Does the semantics of java volatile guarantee that wrong results will not appear? (Two threads write first and then read)
volatile x=y=0
Thread1
x=1
r1=y
Thread2
y=1
r2=x
r1 和 r2 是局部变量
问题一:
r1==r2==0
的结果是非法的,没有出现吗?
所有语句都是写入或读取volatile字段,按常理应该是r1==1
或r2==1
或r1==r2==1
三种情况之一
让我困惑的是,volatile的语义是当read看到write的结果时,happens-before规则成立。在这个测试中,如果两个线程看不到对方的结果,并不违反happens-before 的规则(更新:这是错误的).
JLS 说 happens-before rules is not enough, And there is a Causality Test Cases。我把它理解为一些补充的特殊情况规则,但是我在那些例外规则中没有找到这个问题的情况。
OOTA 问题需要因果关系。
想象一下下面的代码:
int a=0,b=0 (non volatile!)
thread1:
r1=a
b=r1
thread2:
r2=b
b=42
r1==r2==42 是否允许执行?是的,因为 x,y 不是易变的,读取可以看到他们正在竞争的值。这符合happens-before的定义一致:
- 读取需要按照 happens-before 顺序查看最近的写入
- 读取需要看到它在 data-race 中的写入。
如果您有数据竞争,您可能会得到顺序不一致的执行。
如果我们稍微修改示例:
int a=0,b=0 (non volatile!)
thread1:
r1=a (1)
b=r1 (2)
thread2:
r2=b (3)
b=r2 (4)
我们能得到'r1==r2==42'吗?假设我们有一些神奇的 CPU 推测 b=42 在 (3):
所以我们得到:
speculate b=42
r2=42 (3)
b=42 (4)
r1=42 (1)
b=42 (2)
CPU 的推测得到了回报,因为 b=42 的推测是正确的!
值42凭空出现,被JMM禁止。为了解决这个问题,每次执行都需要有一些因果顺序,以防止因果循环。
关于问题 1:
Is the result of r1==r2==0 illegal and does not appear?
是的,这是非法的。由于每个变量都是易变的,因此不存在数据竞争,因此只允许顺序一致的执行。
您的问题是您没有看到程序顺序需要在连续一致的执行中得到保留。
volatile x=y=0
Thread1
x=1 (1)
r1=y (2)
Thread2
y=1 (3)
r2=x (4)
(1) 由于程序顺序发生在 (2) 之前。
(3) 由于程序顺序发生在 (4) 之前。
在 JMM 中,happens-before 关系被定义为程序顺序和 synchronizes-with 顺序并集的传递闭包。
volatile x=y=0
Thread1
x=1
r1=y
Thread2
y=1
r2=x
r1 和 r2 是局部变量
问题一:
r1==r2==0
的结果是非法的,没有出现吗?
所有语句都是写入或读取volatile字段,按常理应该是r1==1
或r2==1
或r1==r2==1
三种情况之一
让我困惑的是,volatile的语义是当read看到write的结果时,happens-before规则成立。在这个测试中,如果两个线程看不到对方的结果,并不违反happens-before 的规则(更新:这是错误的).
JLS 说 happens-before rules is not enough, And there is a Causality Test Cases。我把它理解为一些补充的特殊情况规则,但是我在那些例外规则中没有找到这个问题的情况。
OOTA 问题需要因果关系。
想象一下下面的代码:
int a=0,b=0 (non volatile!)
thread1:
r1=a
b=r1
thread2:
r2=b
b=42
r1==r2==42 是否允许执行?是的,因为 x,y 不是易变的,读取可以看到他们正在竞争的值。这符合happens-before的定义一致:
- 读取需要按照 happens-before 顺序查看最近的写入
- 读取需要看到它在 data-race 中的写入。
如果您有数据竞争,您可能会得到顺序不一致的执行。
如果我们稍微修改示例:
int a=0,b=0 (non volatile!)
thread1:
r1=a (1)
b=r1 (2)
thread2:
r2=b (3)
b=r2 (4)
我们能得到'r1==r2==42'吗?假设我们有一些神奇的 CPU 推测 b=42 在 (3):
所以我们得到:
speculate b=42
r2=42 (3)
b=42 (4)
r1=42 (1)
b=42 (2)
CPU 的推测得到了回报,因为 b=42 的推测是正确的!
值42凭空出现,被JMM禁止。为了解决这个问题,每次执行都需要有一些因果顺序,以防止因果循环。
关于问题 1:
Is the result of r1==r2==0 illegal and does not appear?
是的,这是非法的。由于每个变量都是易变的,因此不存在数据竞争,因此只允许顺序一致的执行。
您的问题是您没有看到程序顺序需要在连续一致的执行中得到保留。
volatile x=y=0
Thread1
x=1 (1)
r1=y (2)
Thread2
y=1 (3)
r2=x (4)
(1) 由于程序顺序发生在 (2) 之前。
(3) 由于程序顺序发生在 (4) 之前。
在 JMM 中,happens-before 关系被定义为程序顺序和 synchronizes-with 顺序并集的传递闭包。