voliate实现原理总结---Java

先说结论

volatile三个特点

  1. 如果一个字段被申明为volatile,那么Java内存模型则可以保证多个线程所看到的值是一致的
  2. 禁止指定重排。
  3. volatile只能保证可见性,不能保证原子性。

volatile定义和实现原理

java语言规范第三版中对volatile的定义如下:Java编程语言允许线程访问共享变量,为了确保共享变量能被准确和一致地更新,线程应该确保通过排他锁单独获得这个变量。

可见性实现原理:

volatile能够保证可见性,那么它是如何实现可见性的呢?以X86处理器为例,在对volatile修饰的变量进行写操作时,通过编译器生成反汇编指令后,会发现会多一条Lock前缀,就是由于这条Lock前缀所实现的可见性。Lock前缀在多核处理器中会引发下面这两件事情:

  1. Lock指令会将当前处理器缓存行的数据写回到主内存。(ps:每个处理器都有自己的cache缓存,每次缓存中操作的变量都是主内存中变量的拷贝)
  2. 一个处理器写回主内存的操作会造成其他处理的缓存无效

禁止指令重排原理:

总结的一句话就是通过内存屏障来实现禁止指令重排。详细原理建议查看相关数据或者文章。

不能保证原子性:

典型的例子就是i++的情景,详见我的这篇文章:Java原子操作的两种方法及实现原理

volatile的使用优化

在JDK7的并发包里新增了一个队列集合类LinkedTransferQueue,它在使用volatile变量的时候,会采用一种将字节追加到64字节的方法来提高性能。那为什么追加到64字节能够优化性能呢?

这是因为在很多处理器中它们的L1、L2、L3缓存的高速缓存行都是64字节宽,不支持填充缓存行,例如,现在有两个不足64字节的变量AB,那么在AB变量写入缓存行时会将AB变量的部分数据一起写入一个缓存行中,那么在CPU1和CPU2想同时访问AB变量时是无法实现的,也就是想同时访问一个缓存行的时候会引起冲突,如果可以填充到64字节,AB两个变量会分别写入到两个缓存行中,这样就可以并发,同时进行变量访问,从而提高效率

 

 

参考文献:

Java并发编程的艺术

你可能感兴趣的:(java多线程)