java并发编程学习(二) volatile

来源:互联网 发布:熊猫杀姐姐知乎 编辑:程序博客网 时间:2024/06/05 03:13

       在多线程并发中,synchronize和volatile都扮演重要角色,volatile是轻量级的synchronized,在多线程开发中保证了共享变量的可见性。可见性指的是当一个线程修改一个共享变量时候,另一个线程能读到这个修改的值。

       如果volatile变量修饰符使用得当的话,它比synchronized的使用和执行成本更低,因为他不会引起线程的上下文切换和调度,如果一个变量声明为volatile的,java线程内存模型确保所有线程看到这个变量的值是一致的。

1. volatile的定义和实现原理

先了解下实现原理相关的cpu术语和说明

cpu的术语定义术语描述内存屏障一组处理器指令实现对内存操作的顺序限制行缓中可以分配的最小存储单位原子操作不可中断的一个或者一组操作缓存行填充当处理器识别到从内存中读取的操作数是可缓存的,处理器读取整个缓存行到适当的缓存中缓存命中如果进行高速缓存行中填充操作的内存位置,仍然是下次处理器访问的位置,处理器从缓存中读取数据而不是内存中写命中当处理器将操作数写入到内存缓存的区域时候,先检查一个缓存的内存地址是否在缓存行中,如果存在一个有效的缓存行,就写入到缓存行中,而不是内存中写缺失一个有效的缓存行写入到不存在的内存区域

      volatile是如何保证可见性的?

java代码如下:

      instance = new Instance(); //instance是volatile修饰的变量  对它进行写操作,转为汇编语言

汇编代码 : xxxxx ;  lock add1 $0*0,($esp);

      lock前缀的指令在多核处理器下,触发两件事:

1>  将当前处理器缓冲行的数据写入到内存中

2>  这个写操作会使得在其他cpu里面缓存了该内存地址的数据无效

     为了提高处理速度,处理器不会直接和内存进行通信,而是将系统内存的数据读到内部缓存中后在进行操作,但是操作完不知道何时写入到内存中。如果对volatile变量执行写操作,jvm会向处理器发送一个lock前缀的指令,将这个变量所在缓存行的数据写入到内存中。但是,如果其他处理器缓存的值还是旧的,在执行运算还是有差错的,所以,在多处理器下,为了保证各个处理器缓存数据的一致,会实现缓存一致性协议。

    每个处理器嗅探在总线上传播的数据来检查自己缓存的值是否过期了,当处理器发现自己缓存行对应的内存地址被修改时候,就会将当前处理器的缓存行的数据设置为无效状态,当处理器对这个数据进行修改,就会重新冲内存中取值,读到缓存行中。

总的来说,volatile的两条实现原则
1>  lock前缀的指令会将处理器缓存会写到内存中。

2>  一个处理器的缓存会写到内存中会导致其他处理器的缓存无效。