并发--总结
MESI和高速缓存
硬件再单核时代为了提高cpu的使用率所以在主内存和cpu之间加入了高速缓存,这样的好处是cpu可以快速对数据进行指令操作。
当多核时代到来由于每个核心都有自己的高速缓存,但是又共享主内存。这就会导致各个处理器之间的缓存数据不一致。为了解决缓存不一致的情况
出现了许多的缓存一致性协议,比较熟悉的就是MESI协议。虽然缓存一致性协议解决了共享变量一致性问题,但是因为其性能较差,所以又引入了写缓冲
和无效队列。这个引入也会导致共享变量一致性问题和伪重排序问题。为了解决一致性和真伪重排序问题,各个硬件又开始支持了内存屏障,虽然实现细节有所不同
但是大致是相似的。
JMM
说回JMM,java为了屏蔽各个硬件和操作系统访问内存的差异(类似于接口,规定了内存模型和访问规则,各个JVM团队在不同的硬件和操作系统上实现即可,细节可以不一样)
整个内存模型借鉴了我们之前说的cpu和主内存之间的操作,java 也规定了自己的主内存(是jvm的主内存,也属于os内存的一部分),同时还有各个工作内存(类似于高速缓存),各个线程类似于处理器。
而java提供的voliatile和synchronized 底层都是依托内存屏障,让指令不会重排序同时又可以让读写操作按照指令顺序正常执行完毕。
JAVA规定了内存间交互操作
- 1.规定了java工作内存和主内存的交互规则
内存交互必须满足的规则
- 1.确定了一些原则 其中对lock和unlock操作时候会需要对变量 进行的值进行更新和同步这就需要内存屏障
HappenBefore
- 1.通过该规则避免了内存模型中所有的有序性都只靠volatile和synchronized完成
对象头
CAS
- 1.依靠lock信号来实现,虽然不是内存屏障但是又mfence的语义
- 2.因为还需要额外锁住总线和缓存上锁,成本更高。
流程如下:
- 1.对总线和缓存上锁
- 2.强制所有lock信号前的指令都执行完毕,并同步完成相关缓存
- 3.执行lock后指令
- 4.释放总线和缓存上的锁
- 5.强制所有lock信号后的指令都在此之后被执行并同步相关缓存。
As-If-Serial
- 1.不管怎么重排序(编译器和处理器为了提高并行度),(单线程)程序的执行结果不能被改变
- 2.为了遵守as-if-serial语义,编译器和处理器不会对存在数据依赖关系的操作做重排序
mfence和sfence
mfence
- 1.全能屏障
sfence
- 1.保证sfence之前的store执行完毕再执行sfence指令之后的store执行
- 2.不影响load命令的乱序
- 3.StoreStore Barriers
lfence
- 1.LoadLoad Barriers。
final
- 1.依靠sfence
网友评论