受此启发question ,我写了测试:
public class Main {
private static final long TEST_NUMBERS = 5L;
private static final long ITERATION_NUMBER = 100000L;
private static long value;
public static void main(final String [] args) throws Throwable {
for(int i=0; i<TEST_NUMBERS; i++) {
value = 0;
final Thread incrementor = new Thread(new Incrementor());
final Thread checker = new Thread(new Checker());
incrementer.start();
checker.start();
checker.join();
incrementer.join();
}
}
static class Incrementor implements Runnable {
public void run() {
for(int i=0; i<ITERATION_NUMBER; i++){
++value;
}
}
}
static class Checker implements Runnable {
public void run() {
long nonEqualsCount = 0;
for(int i=0; i<ITERATION_NUMBER; i++){
if(value != value) {
++nonEqualsCount;
}
}
System.out.println("nonEqualsCount = " + nonEqualsCount);
}
}
}
这个程序在普通情况下被打印出来:
nonEqualsCount = 12; //or other non 0 value;
nonEqualsCount = 0;
nonEqualsCount = 0;
nonEqualsCount = 0;
nonEqualsCount = 0;
首先:我解释这种行为是因为 JIT 编译器的存在。 “预热”后每个线程的 JIT 编译器缓存值非 volatile
字段。对吗?
第二:如果第一对不对,如何验证?
附言- 我知道 PrintAssebly-选项。
更新:环境:Windows 7 64 位,JDK 1.7.0_40-b43(热点)。
最佳答案
递增 long
变量不是原子的(64 位大)。
在条件 (value != value)
中:可能会发生在读取 value
的值之间,第一个线程可以更改值。
volatile
类型与visibility
相关。非 volatile 变量值可能是陈旧的。所以你的第一个结论似乎是正确的。
关于java - JIT 是这种行为的原因吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19807473/