volatile语义


volatile在Java内存模型(JMM)中,保证共享变量对全部线程可见,但不保证原子性。volatile语义是同步,经过共享变量的方式,完成线程间的通讯。
html

为何须要volatile

Java内存模型中抽象、简化了计算机物理设备,分红工做内存和主内存,线程有各自的工做内存,却共享主内存。若是要把Java内存模型与物理设备映射起来的话,L1,L2 Cache能够视为工做内存,而L3 Cache视为主内存。线程执行指令时,会优先选择距离 CPU 较近的位置的工做内存中使用,而不会从读写速度较慢的主内存中,我称之为“就近原则”。当线程指令执行完后,赋值给工做内存,若是不回写到主内存,或者通知其余线程,其余线程是没法知晓变量已经修改,仍然会使用曾经缓存在工做内存中的变量,这就形成了缓存不一致的问题,Java使用volatile解决这种问题。volatile保证指令赋值完后的变量当即同步回主内存中,声明并通知其余线程当前赋值的变量已经失效,其余线程在下次使用时会放弃工做内存中变量,使用主内存中的变量。这样就完成了线程间对于volatile修饰的变量的通讯。java

可见性

执行引擎只与工做内存交互,再有工做内存与主内存交互。站在执行引擎的角度,与工做内存操做完成即表示指令执行完,可是何时工做内存会将结果刷新回主内存却不可预测。Java线程间的通讯是经过共享内存的方式,线程A若是想通知其余全部线程(线程B,线程C)对于变量f的变化状况,须要知足两点:编程

  1. 将变量回写到主内存中
  2. 执行引擎读取时强制从主内存中加载
    在增长了增长了L一、L2 Cache以后,CPU什么时候将变量从独享缓存刷新会共享内存,独享缓存是否从共享内存加载变量,时间上都是不可肯定的,这就形成了缓存不一致的问题。

可见性的语义是线程对变量更新操做后,其余线程是能够获知变量的变动状况。
工做内存和主内存关系工做内存和主内存关系缓存

原子性

原子操做是一个或多个不可中断的操做,要么一次性彻底执行完毕,要么就不执行,最终状态不存在有些操做执行完,有些操做没有执行,在外部看来是不可分割的总体(好比化学中的原子,固然原子也是能够再分割的,不过站在分子层面,原子是最小的不可分割的),原子操做关注的是不被线程调度器中断的操做。安全

原子性操做是不会出现线程交替执行的状况,若是出现线程交替,则说明操做被线程调度器中断。在Java内存模型中,原子性保证你获取的变量要么是初始值,要么是被某一个线程写入的值,而不会是有多个线程同一时间写入而产生的混乱结果,long或double类型除外(由于变量的前32位可能由一个线程写入,后32位由另外一个不一样的线程写入),不过加上volatile修饰后的long 和double也具备原子性。并发

注意:volatile关注可见性,而与原子性没有关系。volatile关注点在于从工做内存刷新回主内存,而原子操做关注的是否不被打断。原子和同步目的都是让不一样线程能够安全地访问共享变量的两种处理方式,避免形成内存一致性错误。oracle

我是葛一凡,但愿对你有帮助。post

参考

  1. 聊聊并发(一)深刻分析Volatile的实现原理
  2. 聊聊并发(五)——原子操做的实现原理
  3. Java Language Specification
  4. Java Volatile 关键字详解
  5. 从缓存行出发理解volatile变量、伪共享False sharing、disruptor
  6. Java并发编程:volatile关键字解析
  7. Java 编程要点之并发(Concurrency)详解
  8. Java 并发编程(1): Java 内存模型(JMM)
相关文章
相关标签/搜索