基本知识
- Java程序默认采用混合执行模式,即既有解释运行,也有JIT编译运行。
- Java程序运行期间,先解释运行,在一定条件下触发JIT编译运行。
- JIT编译器编译判决条件基于方法调用计数器和方法中的循环回边计数器。
- 循环的回边计数器超过阈值,循环可以被编译,这种编译称作OSR编译(栈上替换)。
- 计数器会周期性减少,这意味着计数器只是方法或循坏最新热度的度量。
测试目的
- 查看非volatile变量读写在多线程环境中解释运行和编译运行下的结果
测试代码
public class Test {
//static变量线程间共享,停止标志
static boolean stopFlag = false;
public static void main(String[] args) {
Runnable runnable = new Runnable() {
public void run() {
//自旋
while (!stopFlag);
}
};
//读线程
new Thread(runnable).start();
//main线程休眠1s,之后修改stopFlag
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//写线程
stopFlag = true;
}
}
idea修改程序运行JVM参数
JVM参数解释
- -XX:+PrintCompilation :打印编译日志
- -Xint:只解释运行,不启用编译运行
- -Xcomp:不启用解释运行,只启用JIT编译运行
结果
- 程序在解释运行下1秒后正常停止。
- 程序在编译运行下main线程停止,另一个线程依然在跑。
结论
- 在Java编程中,对于在多线程进行读写的变量最好加上volatile关键字,因为在测试中不一定会触发JIT编译,从而问题没有爆发出来。在JDK中,并发工具类ConcurrentHashMap对可能在多线程中读写的变量基本采用了volatile关键字进行声明。