Java内存模型之happens-before_java happens-before


上述代码存在如下happens-before关系:


1. A happens-before B
2. B happens-before C
3. A happens-before C


这3个happens-before关系中,第二个和第三个是必须的,而第一个是非必须的(A、B操作之间重排序,程序执行结果不会发生改变)。  
 JMM把happens-before要求禁止的重排序分为下面的两类:


1. 会改变程序执行结果的重排序
2. 不会改变程序执行结果的重排序


JMM对这两种不同性质的重排序,采取了不同的策略:


1. 对于会改变程序执行结果的重排序,JMM要求编译器和处理器必须禁止
2. 对于不会改变程序执行结果的重排序,JMM不做要求(JMM运行)


​


**JMM设计示意图:**  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210612213035441.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQxMTI1MjE5,size_16,color_FFFFFF,t_70#pic_center)




**JMM设计示意图**


**总结:**


* JMM给程序员提供的happens-before规则能满足程序员的需求。简单易懂,具有足够强的内存可见性保证。
* JMM对编译器和处理器的束缚尽可能少。遵循的原则是:不改变程序的执行结果(正确同步或单线程执行),编译器和处理器可以任意优化。


#### 2、happens-before的定义


**起源:**  
 happens-before规则来源于Leslie Lamport《Time, Clocks and the Ordering of Events in a Distributed System》。该论文中使用happens-before来定义分布式系统中事件之间的偏序关系(partial ordering),该文中给出了一个分布式算法,能用来将偏序关系扩展为某种全序关系。  
 ​


**Java中的应用:**  
 JSR-133使用happens-before来指定两个操作之间的执行顺序。JMM可以通过happens-before关系向程序员提供跨线程的内存可见性保证。  
 ​


《JSR-133:Java Memory Model and Thread Specification》对happens-before关系的定义如下:


1. 如果操作A happens-before 操作B,那么A操作的执行结果将会对操作B可见,且操作A的执行顺序排在操作B之前——JMM对程序员的承诺
2. 两个操作存在happens-before关系,并不意味着Java平台的具体实现必须按照happens-before的顺序来执行。如果重排序不改变程序执行结果(与happens-before)规则一致,那么这种重排序是不非法的(JMM允许这种重排序)。——JMM对编译器和处理器的束缚原则


​  
 **happens-before和as-if-serial语义:**  
 从上述来看,happens-before和as-if-serial语义本质上是一回事


* as-if-serial语义保证单线程内程序的执行结果不被改变,happens-before关系保证正确同步的多线程程序的执行结果不改变
* as-if-serial语义给编程者一种单线程是按程序顺序执行的幻境;happens-before关系给编程者一种正确同步的多线程是按照happens-before指定的顺序执行的幻境。


两者的目的都是为了在不改变程序执行结果的前提下,尽可能的提高程序的执行效率。  
 ​


#### 3、happens-before规则


《JSR-133:Java Memory Model and Thread Specification》定义了如下happens-before规则


1. 程序顺序规则
2. 监视器锁规则
3. volatile变量规则
4. 传递性
5. start()规则
6. join()规则


​


##### 3.1 volatile写-读


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


![在这里插入图片描述](https://img-blog.csdnimg.cn/20210612213253388.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQxMTI1MjE5,size_16,color_FFFFFF,t_70#pic_center)  
 



**happens-before关系示意图**

  

**分析上图:**

1. 1 happens-before 2和3 happens-before 4由程序顺序规则产生。由于编译器和处理器遵循as-if-serial语义,也就是说,as-if-serial语义保证了程序顺序规则。因此可以把程序顺序规则看成是对as-if-serial语义的“封装”。
2. 2 happens-before 3 是有volatile规则产生。一个volatile变量的读,总是能看到(任意线程)对这个volatile变量的最后写入。
3. 1 happens-before 4 是由传递性规则产生的。这里的传递性是由volatile的内存屏障插入策略和volatile的编译器重排序规则来共同保证的。


​


​


##### 3.2 start()规则


假设线程A在执行的过程中,通过执行ThreadB.start()来启动线程B;同时,假设线程A在执行ThreadB.start()之前修改了一个共享变量,线程B在执行后会读取这些共享变量。  
 start()程序对应的happens-before关系图:  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210612213613929.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQxMTI1MjE5,size_16,color_FFFFFF,t_70#pic_center)
  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值