java并发系列-Volatile

 volatile 定义

       在多线程并发编程中synchronized和Volatile都扮演着重要的角色,Volatile是轻量级的synchronized,它在多处理器开发中保证了共享变量的“可见性”。可见性的意思是当一个线程修改一个共享变量时,另外一个线程能读到这个修改的值。它在某些情况下比synchronized的开销更小,本文将深入分析在硬件层面上Inter处理器是如何实现Volatile的。

          Java语言规范第三版中对volatile的定义如下: java编程语言允许线程访问共享变量,为了确保共享变量能被准确和一致的更新,线程应该确保通过排他锁单独获得这个变量。Java语言提供了volatile,在某些情况下比锁更加方便。如果一个字段被声明成volatile,java线程内存模型确保所有线程看到这个变量的值是一致的。

volatile实现原理

     有volatile变量修饰的共享变量进行写操作的时候,编译器会增加汇编代码LOCK,lock前缀的指令在多核处理器下会引发了两件事情。
将当前处理器缓存行的数据会写回到系统内存。
这个写回内存的操作会引起在其他CPU里缓存了该内存地址的数据无效。

《java并发编程艺术》第二章对此有详细的介绍。下面结合第三章 Java内存模型来看。

volatile 的内存语义

volatile的内存语义

看看上面这个图,结合之前的文字介绍,就清晰了不少。

volatile写的内存语义:

   当写一个volatile变量时,JMM会把改线程对应的本地内存中的共享变量值刷新到主内存。

volatile 读内存语义:

  当读取一个volatile变量时,JMM会把该线程对应的本地内存置为无效。线程接下来将从主内存读取共享变量。

volatile内存语义的实现

     可以从JMM看如何实现volatile内存语义。在执行程序时为了提高性能,编译器跟处理器经常对指令进行重排序,这些重排序可能会对多线程程序出现内存可见性问题,对于编译器,JMM的编译器重排序规则会禁止编译器对特定类型的编译器重排序,对于处理器,JMM的处理器重排序规则要求java编译器在生成字节码时,会在指令序列插入内存屏障来禁止特定类型的处理器重排序。为了实现volatile的内存语义,编译器在生成字节码时,会在指令序列插入内存屏障来禁止特定类型的处理器重排序。

   内存屏障(Memory Barrier,或有时叫做内存栅栏,Memory Fence)是一种CPU指令,用于控制特定条件下的重排序和内存可见性问题。Java编译器也会根据内存屏障的规则禁止重排序。
      内存屏障可以被分为以下几种类型
LoadLoad屏障:对于这样的语句Load1; LoadLoad; Load2,在Load2及后续读取操作要读取的数据被访问前,保证Load1要读取的数据被读取完毕。
StoreStore屏障:对于这样的语句Store1; StoreStore; Store2,在Store2及后续写入操作执行前,保证Store1的写入操作对其它处理器可见。
LoadStore屏障:对于这样的语句Load1; LoadStore; Store2,在Store2及后续写入操作被刷出前,保证Load1要读取的数据被读取完毕。
StoreLoad屏障:对于这样的语句Store1; StoreLoad; Load2,在Load2及后续所有读取操作执行前,保证Store1的写入对所有处理器可见。它的开销是四种屏障中最大的。        在大多数处理器的实现中,这个屏障是个万能屏障,兼具其它三种内存屏障的功能。

     JMM采用了storeload,这种策略非常保守,但是可以保证跨处理器平台正确的得到volatile内存语义。这里可以理解为优先保证正确性,再追求效率。

volatile特点:
可见性:对于一个 volatile变量的读,总能看到任意线程对这个 volatile变量最后的写入。
原子性:对于任意单个 volatile变量的读写具有原子性,但是类似于 volatile++这种复合操作不具备原子性。
有序性:主要是禁止指令重排序。
         适应场景:单个线程写,多个线程读。提供一种比锁更轻量级的通信机制。在功能上锁比 volatile功能更强大,可提供整个临界区代码的执行具有原子性。在执行性能上, volatile更有优势。所以如果想用 volatile替代锁,要注意场景:1)对变量的写操作不依赖于当前值,2)该变量没有包含在具有其他变量的不变式中。其实就是为了保证操作是原子性的。
        印象中juc里面的volatile跟CAS一起使用,来实现原子操作。

*****************************************
对于Java内存模型来说,工作内存是个虚拟概念。jvm找不到的。所以要从编译器跟处理器角度去看。最后还是要多看并发编程网上有关文章,书上第三章Java内存模型对此作了详细介绍:介绍了重排序,happens-before, as-if-serial.

参考:http://ifeve.com/volatile/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值