【JVM】JMM/ java内存模型

硬件层的并发优化基础知识

数据层一致协议

每个cpu有内部的高速缓存区,也有外部的高速缓存或者内存。当一个数据在外部高速缓存或者内存中,当cpu要处理数据的时候,会先查内部高速缓存,再查外部高速缓存,再查内存,将数据拿回来处理,那么多个cpu同时处理一个数据,如何保证数据一致性?

在老的cpu中,会对总线加锁,这样效率很低。所以在新的cpu中,会使用各种各样的数据层一致协议,因特尔使用的MESI协议,还有各种其他协议

MESI协议

MESI缓存锁。内存中保存对象的4个状态,通过4个状态来保证数据一致性

  • Modified 当前cpu修改过
  • Exclusive 只有当前cpu在用
  • Shared 当前cpu和其他cpu都在用
  • invalid 数据已经被别的cpu修改过

但是当遇到无法缓存的数据(例如数据过大、或者跨越多个缓存),则缓存锁失效。此时就需要总线锁配合。

所以现在cpu的数据一致性=缓存锁(MESI)+总线锁

cacheline 缓存行对齐 伪共享

cpu从内存中读取数据的时候,会读取整行数据(一般为64字节),例如有一个int类型,4字节。cpu读取的时候,不仅仅是读取4个字节,而且读取了4个字节和之后的60个字节。这64个字节就是缓存行。

伪共享:当2个数据在同一个缓存行的时候,2个cpu一个修改x,一个修改y,就会互相影响,互相让对方更新数据。但其实每个cpu只用到了自己想用的数据。

面试题:位于同一缓存行的两个不同数据,被2个不同cpu锁定,产生互相影响的伪共享问题

使用缓存行对齐,就可以提高效率。比如一个long对象占了8字节,那么声明的时候,可以在前创建7个对象,后创建7个对象,保证这个对象单独的占据一个缓存行,不和其他对象公用一个缓存行。

 

cpu乱序问题

cpu运算速度是内存的100倍,那为了提高指令执行效率,会在一条指令执行过程中,去同时执行另一条指令,前提是两条指令没有依赖关系。比如第一条cpu指令在执行时,还在等待内存的响应,其他指令也在分析与运行

写也可以同时进行。比如cpu要把一个值写入到内存中,但是因为内存运算速度慢,还没写进去的时候,cpu又操作了这个值,又要保存一次。此时,cpu会把相同的写入操作,放到wc(wirteCombining) buffer中,一次执行。

现在的wc buffer只有4个位置,操作指令大于4个位置的,就要分多次写

如何保证特定情况不乱序?

硬件级别:

cpu内存屏障 ,不同cpu不同

x86cpu,

sfence:s =save在sfence指令前的写操作必须在sfence指令后的写操作前完成

lfence:l = load在lfence指令前的读操作必须在lfence指令后的读操作前完成

mfence:m = 在mfence指令前的读写操作必须在mfence指令后的读写操作前完成

lock指令

 

jvm级别如何规范(JSR133)

jvm的有序性,可以基于多种硬件级别的保证方式来实现.其实就是jvm用硬件级别的各种方式,实现各种有序。

  1. LoadLoad屏障
    1. 对于这样的语句load1;loadLoad;load2,在load2以及后续的读取操作要读取的数据被访问前,保证load1读取的数据读取完毕
  2. StoreStore屏障
    1. 对于这样的语句store1;storeStore;store2,在store2以及后续的写入操作前,保证store1的写入操作对其他处理器可见
  3. LoadStore屏障
    1. 对于这样的语句Load1;loadStore;store2,在store2以及后续的写入操作前,保证load1读取的数据读取完毕
  4. StoreLoad屏障
    1. 对于这样的语句store1;storeLoad;load2,在load2以及后续的读取操作前,保证store1的写入操作对其他处理器可见

volatile 的实现细节

volatile关键字,会先变成字节码,再给jvm,最后由jvm调用操作系统来实现。所以要按层级来看3个地方的实现

  1. 字节码层面:字节码层面只加了VOLATILE
  2. jvm层面:
    1. 在volatile写操作:storeStoreBarrier,volatile写,StoreLoadBarrier.
    2. 在volatile读操作:LoadLoadBarrier,volatile读,LoadStoreBarrier
  3. os和硬件层面
    1. windows是用lock指令实现

synchronized的实现细节

  1. 字节码层面:
    1. 在方法前加锁和volatile类似,在access_flag增加了一个synchronized
    2. 在方法内加锁,是增加了一条monitorenter和两条monitorexit两条指令(一条是正常退出,一条是发生异常退出)
  2. jvm层面:c c++调用了操作系统提供的同步机制
  3. os和硬件层面
    1. X86 lock指令实现
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值