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; //省略其他代码 }因为使用追加字节的方式需要处理器读取更多的字节到高速缓冲区,这本身就会带来一定的性能消耗,共享变量如果不被频繁写的话,锁的几率也非常小,就没必要通过追加字节的方式来避免相互锁定。
|
|