您现在的位置是:首页 > 文章详情

Java内存模型-volatile内存语义

日期:2018-05-07点击:468

章节目录

  • 1.volatile 的特性
    • 为什么volatile修饰变量的写操作不是原子性的?
  • 2.volatile 写-读建立的 happens-before 关系
  • 3.volatile 写-读的内存语义

1.volatile 的特性

首先应该明确的一点是:当声明共享变量为volatile后,对这个变量的读/写(分为单元素读写,与复合写操作)。不同的读写模式下,volatile变量对写操作的原子性体现是不一样的。

理解volatile特性的一个好办法是把对volatile变量的单个读/写,看成是同一个锁对这些单个读/写操作做了同步,示例代码如下所示:

class VolatileFeaturesExample { volatile long vl = 0L; public void set(long l){ vl = l; } public void getAndIncrement() { vl++; } public long get(){ return vl; } } 

假设有多个线程调用上述程序中的3个方法,这个程序语义和下面的程序语义等价

class VolatileFeaturesExample { long vl = 0L; public synchronized void set(long l){ vl = l; } public void getAndIncrement() { long temp = get(); temp +=1L; set(temp); } public syntronized long get(){ return vl; } } 

解释

  • 如这两个程序所示,一个volatile 变量的单个读/写操作,与一个普通变量的读/写操作都是使用同一个锁来同步,他们之间的执行效果相同。
  • 锁的happens-before规则(保证前一个操作结果对后一个操作立即可见)保证释放锁和获取锁的两个线程之间的内存可见性。这很好的解释了对于一个volatile变量的读,总能看到任意线程对这个volatile变量最后的写入。
  • 锁的语义决定了临界代码区的执行具有原子性。这意味着,即使是64位的long型和double型变量,只要它是volatile变量,对该变量的单个读/写就具有原子性,如果是多个volatile操作,或这是volatile++这种复合操作,这些操作在整体上是不具有原子性的。

volatile 自身特性:

1.内存可见性:对一个volatile变量的读,总能看到任意线程对这个volatile变量 最后的写入(内存可见性保证) 2.原子性:对任意单个volatile变量的单独的读写操作,都具有原子性。但对于 volatile++这种复合操作不具有原子性。 

2.volatile 写-读建立的 happens-before 关系

JMM基于共享内存模型实现线程之间的通信

从jdk1.5 开始 volatile 变量的写-读可以实现线程之间的通信。 

volatile & synchronized内存语义

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

下面为volatile变量示例代码:

class VolatileExample { int a = 0;//其实是线程共享变量 volatile boolean flag = false; public void writer(){ a = 1; //1 flag = true; //2 } public void reader(){ if(flage){ //3 int i = a; //4 ...... } } } 

假设线程A 执行 writer() 方法之后,线程B 执行reader() 方法。根据happens-before 规则,这个过程建立的happens-before规则可以分为三类:
1.根据程序次序规则,1 happens before 2;3 happens before 4.
2.根据volatile规则,2 happens-before 3
3.根据happens-before c传递性规则 1 happens-before 4

图形化形势如下图所示:

img_0d8d80545ee12cce05a4eda864ca0e46.png
volatile-写-读 happens-before 关系

A线程在写一个volatile变量后,B线程读同一个volatile变量。A线程在写volatile之前所有的可见共享变量,在B线程读到同一个volatile变量之后,将立即变得对B线程可见。

4. volatile 写-读的内存语义

** volatile 写内存语义 **

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

volatile 读的内存语义

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

volatile内存语义 总结

  • 线程A 写一个volatile 变量,实质上是线程A 向接下来读取这个volatile变量的某个线程发出了(其对共享变量所做修改的)消息。
  • 线程B 读一个volatile 变量,实质上是线程B 接收了之前某个线程发出的(在写这个volatile变量之前对共享变量所做修改)消息。
  • 线程A 写一个volatile 变量,随后线程B读这个volatile变量。这个过程实质上是线程A通过主内存向线程B发送消息。
原文链接:https://yq.aliyun.com/articles/649965
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章