并发编程系列之volatile内存语义

前言

前面介绍顺序一致性模型时,我们提到了程序如果正确的同步就会具备顺序一致性,这里所说的同步泛指广义上的同步,其中包括就包括同步原语volatile,那么volatile声明的变量为什么就能保证同步呢?这又是如何实现的呢?今天就让我们一起来揭开这神秘的面纱,OK,开始我们今天的并发编程之旅吧。

并发编程系列之volatile内存语义

volatile的特性

volatile特性可以理解为对volatile变量的单个读写,看成是使用了同一个锁对这些单个读写进行了同步,他们之间的执行效果是一样的;volatile变量自身具有下面2种特性:

  • 可见性:对一个volatile变量的读,总是能看到对这个volatile变量最后的写入结果,就是保证最后一次的写入操作一定发生在读操作之前;

  • 原子性:对任意单个volatile变量的读-写具有原子性,但是对于volatile++这种复合操作就不保证其原子性了;

 

并发编程系列之volatile内存语义

volatile写-读的内存语义

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

        并发编程系列之volatile内存语义

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

          并发编程系列之volatile内存语义

并发编程系列之volatile内存语义

volatile内存语义的实现

接下来我们再看看volatile在JMM中是如何实现的,首先看下面这张volatile重排序规则表:

并发编程系列之volatile内存语义

NO表示不允许进行重排序,例如当第一个操作是volatile读时,就不允许重排序,为了实现volatile内存语义,编译器在生成字节码时,会在指令序列中插入内存屏障来禁止特定类型的处理器重排序,下面我们再看看JMM中内存屏障的插入策略:

  • 在每个volatile写操作的前面插入一个StoreStore屏障。这个屏障可以禁止上面的普通写和下面的volatile写发生重排序

  • 在每个volatile写操作的后面插入一个StoreLoad屏障。该屏障可以防止上面的volatile写与下面的volatile读或写操作发生重排序

  • 在每个volatile读操作的后面插入一个LoadLoad屏障。该屏障可以禁止下面所有的普通读操作与上面的volatile读发生重排序

  • 在每个volatile读后面插入一个LoadStore屏障,该屏障可以禁止下面所有的普通写和上面的volatile读发生重排序

     

volatile写插入内存屏障后生成的指令序列

并发编程系列之volatile内存语义

volatile读插入内存屏障后生成的指令序列

并发编程系列之volatile内存语义

 

以上就是同步原语volatile的内存语义,通过这篇文章可以了解到底层是如何保证同步的,希望你能有所收获,感谢阅读!!!