## JMM(Java Momory Model)模型
多线程下java代码的执行顺序,共享变量的读法。
* 编译器优化
* Processor优化
* 缓存优化
会导致代码执行顺序变化
### JMM规范
##### Race condition(竞态条件)
在多线程下,没有依赖关系代码,在执行共享变量读写操作(至少由一个线程写时),并不能保证以编写顺序执行,这成为发生了竞态条件。
竞态条件是为了更好的性能
##### Synchronization Order (同步动作) -一个线程中代码的执行顺序
若要保证多线程下,每个线程的执行顺序按照编写顺序执行,那么必须使用Synchronization Actions来保证
lock,unlock 对性能影响最大,但是最强 Synchronization
原理:
反编译代码后,二进制执行时,通过 monitorenter 加锁, 通过 monitorexit 解锁。
在加锁时候,想系统申请 Monitor 锁,由C++实现。
volatile 方式读写变量 对性能影响其次 - 保证可见性,防止重排序
原理:
写入:
↑ LoadStore + StoreStore
store(操作)
↑ Store ↓Load
读取:
load(操作)
LoadLoad + LoadStore
visibility 及时是多次读取同一变量,所得结果不合理
partial ordering 单个属性注解valatile
volatile 写要放在最后 volatile 读要放在最后
total ordering 全部属性注解valatile
*** CAS(对属性操作的原子性) + volatile = 原子性
VarHandle 方式读写变量,jdk9后推出
###### 内存屏障
共有四种,具体实现与cpu架构相关
1, LoadLoad 防止B的load重排到A的load之前
read(A)
LoadLoad
read(B)
2,LoadStore 读取写入
3,StoreStore 写入写入
4,*StoreLoad(发生在线程切换时,屏障前的改动都会同步到主存中,屏障后的Load获取主存中最新数据) 写入读取
Acquire=LoadLoad + LoadStore
Release=StoreStore + LoadStore
##### Heappens-Before (在命令之前出现) -线程切换时代码执行顺序和可见性
若是变量读写时候发生线程切换(例如:线程1写入x,切换到线程2,线程2读取x)在这些边界的处理上如果有action1优先于action2发生,
那么代码可以按确定的执行顺序执行,称之为Heappens-before order规则
触发Heappens-Before条件
1,线程的启动和运行边界
T1(x = 10) → T1(t2.start())
→ T2(run())
→ T2(x == 10)
2,线程的结束和 join 边界
T1(x = 10) → T1(terminated)
→ T2(t1.join)
→ T2(x == 10)
3,线程的打断和得知打断边界
T1(x = 10) → T1(t2.interrupt())
→ T2(this.isInterrupted())
→ T2(x == 10)
4,unlock 与 lock 边界
T1(x = 10) → T1(unlock(obj))
→ T2(lock(obj))
→ T2(x == 10)
5,volatile write 与 volatile read 边界(写在读的前面才会触发)
T1( volatile x = 10) → T2( volatile x == 10 )
6,传递性
T1(x = 10) → T1(unlock(obj))
→ T2(lock(obj))
→ T2(x == 10)
→ T2(terminated)
→ T3(t2.join())
→ T3(x == 10)
##### Causality(因果律)
代码之间存在依赖关系,及时没有加SA(Synchronization Order, Heappens-Before)操作,代码的执行顺序也是可以预见的
##### 安全发布
若要安全构造对象,并将其共享使用,需要使用fianl或者volatile(加在最后一个赋值的变量)修饰其成员变量,避免使用this溢出情况
#### 总结
##### JMM 研究的是
* 多线程下java的执行顺序,实际代码的执行顺序与你编写的代码顺序不同
* 共享变量的读写操作,在竟态条件下,需要考虑共享变量独写的原子性,可见性,有序性
##### 共享变量的问题起因
* 原子性是由于操作系统的分时机制,线程切换导致的
* 有序性和可见性可能来自于编译器优化,处理器优化,缓存优化
##### JMM制定了一些规则,理解这些规则才能写出正确的线程安全的代码
* 竟态条件会导致代码顺序被重排
* 利用synchronized, volatile 一些SA,可以控制线程内代码的执行顺序
* 线程切换时的执行顺序与可见性,遵守HB规则
* HB规则还不足够,需要因果律作为补充
* 可以通过final或者volatile实现对象的安全发布
##### 从底层理解volatile 与 synchronized
* 内存屏障
* synchronized是如何解决原子性,可见性,有序性问题的,有哪些优化
* volatile 是如何解决可见性,有序性问题的,与cas结合的为例
* VarHandle 是如何解决可见性,有序性问题的
Java Momory Model
最新推荐文章于 2024-07-25 14:31:34 发布