Java内存模型_volatile

volatile变量自身具有下列两点特性:

可见性:锁的happens-before规则保证释放锁和获取锁的两个线程之间的内存可见性。意味着对一个volatile变量的读,总是能看到(任意线程)对这个volatile变量最后的写入。

原子性:对任意单个volatile变量的读/写具有原子性,但类似于volatile++这种复合操作不具有原子性。

从内存语义的角度来说,volatile与锁有相同的效果:volatile写和锁的释放有相同的内存语义;volatile读与—锁的获取—有相同的内存语义。

volatile 写-读的内存语义

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

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

下面对volatile写和volatile读的内存语义做个总结:

  • 线程A写一个volatile变量,实质上是线程A向接下来将要读这个volatile变量的某个线程发出了(其对共享变量所在修改的)消息。
  • 线程B读一个volatile变量,实质上是线程B接收了之前某个线程发出的(在写这个volatile变量之前对共享变量所做修改的)消息。
  • 线程A写一个volatile变量,随后线程B读这个volatile变量,这个过程实质上是线程A通过主内存向线程B发送消息。

volatile重排序规则

  • 当第二个操作是volatile写时,不管第一个操作是什么,都不能重排序。这个规则确保volatile写之前的操作不会被编译器重排序到volatile写之后。
  • 当第一个操作是volatile读时,不管第二个操作是什么,都不能重排序。这个规则确保volatile读之后的操作不会被编译器重排序到volatile读之前。
  • 当第一个操作是volatile写,第二个操作是volatile读或者是volatile写时,不能重排序

为了实现volatile的内存语义,编译器在生成字节码时,会在指令序列中插入内存屏障来禁止特定类型的处理器重排序。

下面是基于保守策略的JMM内存屏障插入策略(这些Store和Loade含义请看我另外一篇博客)http://www.cnblogs.com/prayers/p/7478668.html:

  • 在每个volatile写操作的前面插入一个StoreStore屏障。
  • 在每个volatile写操作的后面插入一个StoreLoad屏障。
  • 在每个volatile读操作的后面插入一个LoadLoad屏障。
  • 在每个volatile读操作的后面插入一个LoadStore屏障。

 

从编译器重排序规则和处理器内存屏障插入策略来看,只要volatile变量与普通变量之间的重排序可能会破坏volatile的内存语意,这种重排序就会被编译器重排序规则和处理器内存屏障插入策略禁止。

 

 

 

 

 

 

 

 

 

    原文作者:动物园里的一只程序猿
    原文地址: https://www.cnblogs.com/prayers/p/7479385.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞