Java并发机制的底层实现原理
注:1.java代码 ----(编译)—>2.字节码----(JVM)—>3.汇编
1.volatile的应用
关键词:轻量级synchronized,共享变量,可见性,上下文切换
问题:volatile作用?
1.确保共享变量能被准确和一致的更新
问题:volatile如何保证可见性的?
1.Lock前缀指令
1.1 lock前缀指令会引发两件事情。
1)将当前处理器缓存行数据写回系统内存
2)使其他CPU内缓存了该地址的数据无效(处理器嗅探总线数据)
问题:volatile两条实现原则?
1.lock前缀指令会引起处理器缓存回写到内存。在声言处理器的LOCK#信号期间,处理器通过锁住总线,独占共享内存。
当然LOCK#信号也不一定会产生,当访问的内存区域已经缓存在处理器的内部的时候,就不会产生LOCK#信号。
此时通过锁定该内存区域并回写到内存,借助缓存一致性机制确保修改的原子性。
2.处理器的缓存回写到内存导致其他处理器的缓存无效。
IA-32和Inter64处理器都是使用MESI(modify(修改),engross(独占),shared(共享),invalid(无效))
控制协议维护缓存的一致性。IA-32和Inter64处理器能嗅探其他处理器访问系统内存和他们的内部缓存,当一个处理器打算
写内存地址,而这个内存地址处于共享状态,当这个讯息被正在嗅探的A处理器检测到时,A会使他自己的缓存行无效,再
下次访问到该无效的缓存行地址时,强制执行缓存行填充。
问题:volatile的使用优化?
1.追加字节。通过将对象字节数追加到能填充一个缓存行,从而提高并发编程的效率。
原理:对于英特尔酷睿i7、酷睿、Atom、NetBurst、Core Solo、Pentium M处理器的L1、L2、L3的高速缓存行是64个字节
宽,不支持部分填充缓存行。当队列的头结点和尾节点之间不足64个字节宽时,处理器会将头结点和尾节点读取在同一个缓
存行,由于多处理器操作,当其中一个处理器试图修改头结点/尾节点时会导致该缓存行被锁定,在缓存一致性协议下,导
致其他处理器不能访问自己的高速缓存行中的尾节点/头结点。但若是高速缓存行能被填满,头结点与尾节点分布在不同缓
存行时就不会出现头节点与尾节点相互锁定的情况。
试用范围:1.缓存行非64位的处理器(可适当调整填充缓存行的字节,达到同样的效果)
2.共享变量不会被频繁的写。
3.搞版本java不适用(考虑其他填充缓存行思路)