java内存模型
1、内存模型
内存模型其实就是在特定的操作协议下,对特定的内存或者高速缓存进行读写访问的抽象过程。在多处理器计算机系统中,每个处理器都有自己的高速缓存,而且所有高速缓存都共享一个主内存:
image.png
缓存一致性是多处理器必须解决的一个问题,当多处理器的任务都涉及到同一块主存区域时,可能导致各处理器的高速缓存数据不一致,这时候如何同步回主存就需要缓存一致性协议来协调;
乱序执行是处理器的一项优化,它只保证最终结果的一致性,但不保证各语句的执行顺序与代码中的顺序一致;
java内存模型和多处理器计算器有很多相似之处:
image.png
内存一致性:每条线程都有自己的工作内存,里面保存了这个线程所用到的变量的主内存副本,线程对变量的所有操作都必须在工作内存中进行,不能直接读取主内存中的数据,相应的,java定义了一套内存访问协议来保证内存一致性;
指令重排序:java虚拟机即时编译器只保证最终结果的一致性,不保证各语句的执行顺序与代码中一致;
2、volatile
volatile是java虚拟机提供的最轻量的同步机制,当一个变量被定义为volatile时,将会具备两种特性:
可见性:当一条线程改变了变量的值后,其他线程可以立马感知到新值;
禁止指令重新排序优化:volatile赋值完成之后的指令不会被重排序到该赋值指令之前;
2.1、可见性
要提醒的是:可见性不代表是并发安全的,volatile保证可见性但是并不保证原子性;
volatile的使用场景:
1、运算结果并不依赖变量的当前值,或者只有单一线程修改变量;
2、变量不与其他变量共同参与不变性约束(因为对其中一个变量值赋值之后并在对其他变量值赋值之前,不变性约束可能失效,个人理解觉得还是原子性问题,所有变量不能同时改变);
2.1、禁止指令重排序优化
在介绍之前,先了解一下线程内表现为串行的语义和内存屏障
内存屏障:指令重排序时不能把内存屏障之后的指令重排序到内存屏障之前;
线程内表现为串行的语义:普通变量仅仅会保证该方法的执行过程中所有依赖赋值结果的地方都能获取到正确的结果,而不能保证赋值的操作顺序是否与代付中的顺序一致,这在单线程的执行过程中是无法感知到的,因而表现为线程内串行。
java内存模型对volatile变量定义的特殊规则:
每次使用volatile变量之前都必须从主内存刷新最新的值;
每次修改完volatile变量后都必须同步到主内存;
volatile修饰的变量不会被指令重排优化;