定义
Java内存模型不是JVM运行时数据区,Java内存模型是由Java语言规范提出,用来描述Java多线程程序在执行时的一些规则,JVM运行时数据区是由Java虚拟机规范提出,用来描述JVM虚拟机的特性。
解决什么问题
- 所见非所得
- 无法肉眼去检测程序的准确性
- 不同的运行平台有不同的表现
- 错误很难重现
package com.hzw.subject1;
public class DemoVisibility {
int i = 0;
boolean isRunning = true;
public static void main(String[] args) throws InterruptedException {
DemoVisibility demo = new DemoVisibility();
new Thread(() -> {
System.out.println("here i am...");
while (demo.isRunning) {
demo.i++;
}
System.out.println(demo.i);
}).start();
Thread.sleep(3000L);
demo.isRunning = false;
System.out.println("shutdown");
}
}
期望结果:
here i am...
i=..
shutdown
实际结果:
here i am...
shutdown
//当使用32位的JDK且VM options设置为client会得到期望结果
为什么会出现这种情况?
由于JIT编译器对代码性能进行了优化
JIT :编译执行,即将Java代码整体打包进行编译执行,并在编译的过程中对代码性能进行了大量的优化
优化前:
boolean isRunning = true;
while(isRunning) {
i++:
}
优化后:
//即当程序中一段代码段时间内被多次重复执行,JIT会对其进行优化,使isRunning产生了可见性问题
if(isRunning) {
while(true) {
i++:
}
}
如何解决-volatile同步关键字
可见性问题:让一个线程对共享变量的修改,能够及时的被其他线程看到。共享变量写完其他线程读不到则有可见性问题
Java内存模型规定:对volatile变量v的写入,与所有其他线程后续读取同步,不能够缓存,阻止了一部分(与被修饰的变量相关)的指令重排,可以解决可见性问题
总结
Java内存模型提出Java程序在执行时的一些规则,具体实现规则解决问题是由JVM和虚拟机规范进行
Java内存模型规则
Shared Variables - 共享变量
可以在线程之间共享的内存称为共享内存或堆内存,共享内存用于储存共享变量(实例字段、静态字段、数组元素)
冲突:如果至少有一个访问是写操作,那么对同一个变量的两次访问是冲突的。即使一读一写,当出现可见性问题时也会发生冲突。
线程间操作的定义
线程间操作指:一个程序执行的操作可被其他线程感知或被其他线程直接影响
Java内存模型只描述线程间操作,不描述线程内操作,线程内操作按照线程内语意执行
线程间操作:read、write、lock、unlock、外部操作、线程的第一个和最后一个操作
对于同步的规则定义
对volatile变量v的写入,与所有其他线程后续对v的读同步(可见)
对于监视器m的解锁与所有后续操作对于m的加锁同步(此处m为锁monitor)
对于每个属性写入默认值(0,false,null)与每个线程对其进行的操作同步、
启动线程的操作与线程中的第一个操作同步
线程T2的最后操作与线程T1发现线程T2已经结束同步
如果线程T1中断了T2,那么线程T1的中断操作与其他所有线程发现T2被中断了同步