黑马程序员技术交流社区

标题: 【广州校区】【原创】volatile底层原理 [打印本页]

作者: 码农苏尼玛    时间: 2019-11-12 15:36
标题: 【广州校区】【原创】volatile底层原理
Volatile的官方定义java语言中volatile定义:
java允许线程访问共享变量为确保共享变量准确一致,现成会确保通过排他锁单独获得变量
因此提供volatile更加直接方便.如果字段生命变成volatilejava现成内存模型确保所有线程看到的变量是一致的
为什么要使用Volatile
volatile变量修饰符使用恰当比序列化的执行成本低
Volatile的实现原理
如何保证可见性?因此x86处理器通过工具JIT编译器生成汇编指令操作CPU
Java代码:
instance = new Singleton();//instance是volatile变量
汇编代码:
0x01a3de1d: movb $0x0,0x1104800(%esi);
0x01a3de24: lock  addl $0x0,(%esp);

有volatile变量修饰共享变量进行操作第二行汇编代码.lock前缀指令在多核处理器引发两个事情
1.将当前处理器缓存行的数据写入系统内存
2.cpu缓存内存地址失效
处理器为了提高处理速度,不直接和内存通讯,是在系统内存的数据读到内部缓存
volatile变量读写操作时候jvm会向着处理器发送lock指令,将变量写入系统内存
那么旧值过期,处理器的值将得到更新
一个处理器的缓存回写到内存会导致其他处理器的缓存无效 。IA-32处理器和Intel 64处理器使用MESI(修改,独占,共享,无效)控制协议去维护内部缓存和其他处理器缓存的一致性。在多核处理器系统中进行操作的时候,IA-32 和Intel 64处理器能嗅探其他处理器访问系统内存和它们的内部缓存。它们使用嗅探技术保证它的内部缓存,系统内存和其他处理器的缓存的数据在总线上保持一致。例如在Pentium和P6 family处理器中,如果通过嗅探一个处理器来检测其他处理器打算写内存地址,而这个地址当前处理共享状态,那么正在嗅探的处理器将无效它的缓存行,在下次访问相同内存地址时,强制执行缓存行填充。
Volatile的使用优化
在jdk7里面增加了集合LinkedTransferQueue
也使用到volatile变量,用一种追加字节方式优化了出队和入队性能
** head of the queue */private transient final PaddedAtomicReference < QNode > head;/** tail of the queue */private transient final PaddedAtomicReference < QNode > tail;static final class PaddedAtomicReference < T > extends AtomicReference < T > {  // enough padding for 64bytes with 4byte refs   Object p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb, pc, pd, pe;  PaddedAtomicReference(T r) {    super(r);  }}public class AtomicReference < V > implements java.io.Serializable {  private volatile V value;  //省略其他代码 }因为使用追加字节的方式需要处理器读取更多的字节到高速缓冲区,这本身就会带来一定的性能消耗,共享变量如果不被频繁写的话,锁的几率也非常小,就没必要通过追加字节的方式来避免相互锁定。







欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2