JMM内存模型
JMM内存简单介绍
java多线程内存模型跟CPU缓存模型类似,是基于CPU缓存模型来建立的,Java线程内存模型是标准化的吗,屏蔽掉了底层不同计算机的区别
相关理解:
1. 主内存中的共享变量会复制到每个线程中
2. 每个线程在各自的工作内存中读取、修改共享变量
3. 线程之间是隔离的,共享变量不可见
Volatile可见性
Volatile只能实现线程间共享变量的可见性,不代表原子性
代码解释
public class VolatileVisibilityTest {
private static boolean initFlag =false;
public static void main(String[] args) throws InterruptedException {
new Thread(()->{
System.out.println("waiting data....");
while (!initFlag){
}
System.out.println("+++++++++++++++++success");
}).start();
Thread.sleep(2000);
new Thread(()->{
prepareData();
}).start();
}
public static void prepareData(){
System.out.println("prepareData start");
initFlag = true;
System.out.println("prepareData end>>>>>>>");
}
}
运行结果
线程1还在执行,其实就是代表线程1中的变量仍是false,线程2中对全局变量initFlag的变更并未同步到线程2中。
在全局变量中使用volatile关键字,线程2修改对全局变量initFlag的变更,线程1能够得到全局变量InitFlag的最新值。
Volatile缓存可见性实现原理
底层实现主要通过汇编lock前缀指令,它会锁定这块内存区域的缓存(缓存行锁定)并回写到主内存
IA-32和Intel 64架构软件开发手册对lock指令的解释:
- 会将当前处理器缓存行的数据立即写回到系统内存
- 这个写回内存的操作会引起在其他CPU里缓存了该内存地址的数据无效(MESI协议)
- 提供内存屏障功能,使lock前后指令不能重排
指令 重排序与内存屏障:
- 并发编程三大特性:可见性、有序性、原子性
- volatile保证可见性与有序性,但是不保证原子性,保证原子性需要借助synchronize这样的锁机制
- 指令重排序:在不影响单线程程序执行结果的前提下,计算机为了最大限度的发挥机器性能,会对机器指令重排序优化
- 重排序会遵循as-if-serial与happens-before原则
JMM原子操作
- read(读取):从主内存读取数据
- load(载入):将住内存读取到的数据写入工作内存
- use(使用) :从工作内存读取数据来计算
- assign(赋值):将计算好的值重新赋值到工作内存中
- store(存储):将工作内存数据写入到主内存中
- write(写入):将stroe过去的变量赋值给主内存中的变量
- lock(锁定):将主内存变量加锁,标识为线程独占标识
- unlock(解锁):将主内存变量解锁,解锁后其他线程可以锁定该变量