美文网首页JVM
JMM之再看看Volatile

JMM之再看看Volatile

作者: AlanKim | 来源:发表于2019-01-23 10:12 被阅读1次
Volatile

具体的可见内存可见性一文中volatile相关的知识。这里只扩充一点,关于volatile的内存屏障。

volatile写

对于volatile变量的写,按照JMM的标准,需要插入两条内存屏障:

StoreStore;

volatile_write_code;

StoreLoad;

解释下,在写volatile之前插入了storestore指令,意味着volatile之前的普通写操作需要先于volatile操作执行,也就是不允许之前的普通写操作,与volatile写操作重排序。符合JMM对volatile关键字的规则。

在写volatile之后,需要加入StoreLoad指令,也就是先把volatile变量的最新值刷新到主内存(store),然后再执行后续的操作。同样不允许volatile写操作与后续的读、写操作重排序。

volatile读

对于volatile的读,按照JMM的标准,同样需要查询两条内存屏障,但是不同于上述的写操作,这块都是插入在volatile_code之后的。

Volatile_read_code;

LoadLoad;

LoadStore;

这里的LoadLoad用于禁止下面的普通读操作与volatile读重排序,LoadStore则禁止普通写操作与volatile读操作重排序。

省略不必要的内存屏障

JMM默认的内存屏障插入策略非常保守,而在实际执行时,可以根据实际情况省略掉不必要的屏障。

例如以下代码:

class VolatileBarrierExample{
  int a;
  
  volatile int v1 = 1;
  
  volatile int v2 = 2;
  
  void readAndWrite(){
    int i = v1;  // 第一个volatile读  code_block_1;
    int j = v2;  // 第二个volatile读  code_block_2;
    a = i + j;   // 普通写            code_block_3;
    v1 = i + 1;  // 第一个volatile写  code_block_4;
    v2 = j * 2;  // 第二个volatile写  code_block_5;
  }
  ...
}

针对readAndWrite方法,理论上编译器在生成字节码的时候会加入如下内存屏障:

code_block_1;   --- a

LoadLoad;  --- b

// LoadStore;  ---- c



code_block_2;  --- d

// LoadLoad;  ---- e
 
LoadStore; --- f



code_block_3; --- g



StoreStore;  --- h

code_block_4; ---i

// StoreLoad; --- j



StoreStore;  ---k

code_block_5; ---l

StoreLoad;  --- m

但是实际上,有些内存屏障是可以省略的,下面详细说下

c — 可以省掉,因为下面的普通读操作g,不可能跳过d语句的执行,d也是一条volatile

e - 可以省掉,因为下面根本没有普通读,g是普通写

j— 可以省略,因为下面紧跟着一条volatile写

所以最终,c e j三行内存屏障被省略了

JSR-133增强了Volatile的内存语义

使得volatile变量写-读 与锁的-释放-加锁具有相同的内存语义,volatile变量与普通变量的处理都做了禁止重排序的设定。

锁的happens-before说明

锁的释放-获取建立的happens-before关系

锁是java并发编程中最重要的同步机制,锁会让临界区互斥,同时释放锁的线程向获取同一个锁的线程发送通知消息。

举个例子:

Class MonitorExample{
  int a = 0;
  
  public synchronized void writer(){   //1
    a ++;  // 2
  } // 3
   
  public synchronized void reader(){ // 4
    int i = a;  // 5
    ......
  }  //6 
}
  • 按照程序顺序原则:

    ​ 1 happens-before 2

    ​ 2 happens-before 3

    ​ 4 happens-before 5

    ​ 5 happens-before 6

  • 按照监视器原则

    ​ 3 happens-before 4 因为3释放锁,4获取同一个锁

  • 按照传递性原则

    ​ 2 happens-before 5,也就是对a的写和读有happens-before关系

假设有两个线程A和B,A先调用writer,然后B调用reader,那么在A执行完之后,在B获取同一个锁,A在释放锁之前所有可见的共享变量,将立即变得对B可见。

相关文章

  • JMM之再看看Volatile

    Volatile 具体的可见内存可见性一文中volatile相关的知识。这里只扩充一点,关于volatile的内存...

  • Java并发编程的艺术

    第三章 volatile 3.4.4 volatile内存语义的实现 为了实现volatile内存语义,JMM会分...

  • java学习笔记

    1.volatile 2.JMM(java内存模型) 3.volatile代码可见性 4.volatile代码不保...

  • JUC编程:Volatile-深入理解CAS-各种锁

    1. JMM 请你谈谈你对 Volatile 的理解 保证可见性 不保证原子性 禁止指令重排 什么是JMM JMM...

  • volatile关键字小总结

    本文内容:1.volatile语义2.由volatile语义引出JMM3.volatile不能保证原子性的解读4....

  • volatile

    一、volatile可见性和禁止重排序是怎么实现的? 首先从JMM内存模型层面,volatile通过storest...

  • 死磕Java——volatile的理解

    一、死磕Java——volatile的理解 1.1.JMM内存模型 理解volatile的相关知识前,先简单的认识...

  • 死磕Java——volatile的理解

    一、死磕Java——volatile的理解 1.1.JMM内存模型 理解volatile的相关知识前,先简单的认识...

  • JMM和volatile

    1JMM(Java Memory Model)JMM是指Java内存模型,不是JVM,不是所谓的栈、堆、⽅法区。每...

  • JMM与volatile

    JMM模型 image.png 八大原子操作 image.png(1)lock(锁定):作用于主内存的变量,把一个...

网友评论

    本文标题:JMM之再看看Volatile

    本文链接:https://www.haomeiwen.com/subject/qjtljqtx.html