[英]Why the volatile Happens-Before order for Instruction Reordering fails?
我hava遵循代码来测试volatile 。 bEnd
和nCount
定义为volatile。
nCount = 0, bEnd = false
Writer线程将设置
nCount = 100, bEnd = true
Reader线程读取这些变量并打印它们。 基于Java Happens-before命令,在我看来, 当bEnd = true时 , volatile确保nCount = 100 。 但有时程序打印这个:
main thread done.
thread Reader running ...
thread Writer running ...
SharedData nCount = 0, bEnd = false
thread Writer bEnd = true
thread Reader nCount = 0, bEnd = true
thread Reader nCount = 100, bEnd = true
thread Reader nCount = 100, bEnd = true
thread Reader done.
Reader如何得到“nCount = 0,bEnd = true” ???
以下代码在windows10,jdk1.8.0_131上运行
public class HappensBeforeWithVolatile {
public static void main(String[] args) {
Thread threadWriter = new Thread(new Writer());
Thread threadReader = new Thread(new Reader());
threadWriter.start();
threadReader.start();
System.out.println("main thread done.");
}
}
class Writer implements Runnable {
@Override
public void run() {
System.out.println("thread Writer running ...");
SharedData.nCount = 100;
// System.out.println("thread Writer nCount = 100");
SharedData.bEnd = true;
System.out.println("thread Writer bEnd = true");
}
}
class Reader implements Runnable {
@Override
public void run() {
System.out.println("thread Reader running ...");
System.out.println("thread Reader nCount = " + SharedData.nCount + ", bEnd = " + SharedData.bEnd);
System.out.println("thread Reader nCount = " + SharedData.nCount + ", bEnd = " + SharedData.bEnd);
if (SharedData.nCount == 0 && SharedData.bEnd) {
System.out.println("thread Reader CODE REORDER !!!");
}
System.out.println("thread Reader nCount = " + SharedData.nCount + ", bEnd = " + SharedData.bEnd);
System.out.println("thread Reader done.");
}
}
class SharedData {
volatile public static boolean bEnd = false;
volatile public static int nCount = 0;
static {
System.out.println("SharedData nCount = " + nCount + ", bEnd = " + bEnd);
}
}
当bEnd = true时,volatile确保nCount = 100
技术上,是的。 但是读者并没有原子地阅读它们。 因此它可能会打印nCount = 0 and bEnd = true
。
这是一个例子:
nCount 0
nCount = 100
bEnd = true
thread Writer bEnd = true
bEnd true
你的整个例子有点瑕疵。 要测试之前发生的情况,您需要测试后续操作,即使bEnd
volatile和nCount
不是volatile,然后将您的示例简化为:
static class Reader implements Runnable {
@Override
public void run() {
while (true) {
if (SharedData.bEnd) {
System.out.println(SharedData.nCount);
break;
} else {
System.out.println("Not yet seen as true");
LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(100));
}
}
}
}
static class Writer implements Runnable {
@Override
public void run() {
LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(1000));
SharedData.nCount = 100;
SharedData.bEnd = true;
}
}
这将输出100
,总是(至少在这种情况下)。 正确的解释是,如果Reader
Thread看到volatile变量的Write
线程的更新,它将看到之前完成的所有事情,因此100
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.