Happens-Before原则和As-If-Serial语义是什么

发布时间:2021-10-12 16:18:06 作者:iii
来源:亿速云 阅读:137

这篇文章主要介绍“Happens-Before原则和As-If-Serial语义是什么”,在日常操作中,相信很多人在Happens-Before原则和As-If-Serial语义是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Happens-Before原则和As-If-Serial语义是什么”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

JMM内存模型

Java内存模型是共享内存的并发模型线程之间主要通过读-写共享变量来完成隐式通信

Java中的共享变量是存储在内存中的,多个线程由其工作内存,其工作方式是将共享内存中的变量拿出来放在工作内存,操作完成后,再将最新的变量放回共享变量,这时其他的线程就可以获取到最新的共享变量。

Happens-Before原则和As-If-Serial语义是什么


从横向去看看,线程A和线程B就好像通过共享变量在进行隐式通信。这其中有很有意思的问题,如果线程A更新后数据并没有及时写回到主存,而此时线程B读到的是过期的数据,这就出现了 “脏读” 现象


     为避免脏读,可以通过同步机制(控制不同线程间操作发生的相对顺序)来解决或者通过volatile关键字使得每次volatile变量都能够强制刷新到主存,从而对每个线程都是可见的。

重排序

执行程序时,为了提高性能,编译器和处理器常常会对指令进行重排序。一般重排序可以分为如下三种:如图,1.属于编译器重排序,而2和3统称为处理器重排序


这些重排序会导致线程安全的问题,一个很经典的例子就是DCL问题。JMM的编译器重排序规则会禁止一些特定类型的编译器重排序;针对处理器重排序,编译器在生成指令序列的时候会通过插入内存屏障指令来禁止某些特殊的处理器重排序

Happens-Before原则和As-If-Serial语义是什么


举个例子:

	public double rectangleArea(double length , double width){
		double leng;
		double wid;
		leng=length;//A
		wid=width;//B
		double area=leng*wid;//C
		return area;
	}

由于A,B之间没有任何关系,对最终结果也不会存在关系,它们之间执行顺序可以重排序。因此可以执行顺序可以是A->B->C或者B->A->C执行最终结果都是3.14,即A和B之间没有数据依赖性。

因为A  happens-before  B,所以A操作产生的结果leng一定要对B操作可见,但是现在B操作并没有用到length,所以这两个操作可以重排序,那A操作是否可以和C操作重排序呢,如果A操作和C操作进行了重排序,因为leng没有被赋值,所以leng=0,area=0*wid也就是area=0;这个结果显然是错误的,所以A操作是不能和C操作进行重排序的(这就是注2中说的前一个操作的执行结果必须对后羿操作可见,如果不满足这个要求就不允许这两个操作进行重排序)

什么是happens-before(面向JMM的规范原则和编译器层面原则) 多线程场景下

JMM可以通过happens-before关系提供跨线程的内存可见性保证如果A线程的写操作a与B线程的读操作b之间存在happens-before关系,尽管a操作和b操作在不同的线程中执行,但JMM向程序员保证a操作将对b操作可见)。

具体的定义:

具体的规则:

// 对一个volatile变量的写操作happen-before对此变量的任意操作:
volatile int a;
a = 1; //1
b = a;  //2
//如果线程1 执行1,“线程2”执行了2,并且“线程1”执行后,“线程2”再执行,那么符合“volatile的
//happen-before原则”所以“线程2”中的a值一定是1。

happens-before具有传递规则

利用程序顺序规则(规则1)存在三个happens-before关系:

这里的第三个关系是利用传递性进行推论的。这里的第三个关系是利用传递性进行推论的

volatile int var;
int b;
int c;
b = 4; //1
var = 3; //2
c = var; //3
c = b; //4

假设“线程1”执行//1 //2这段代码,“线程2”执行//3 //4这段代码。如果某次的执行顺序如下:

//1 //2 //3 //4。那么有如下推导( hd(a,b)表示a happen-before b):

//1 //3 //2// //4 那么最后4的结果就不能确定喽。其原因是 //3 //2 直接符合上述八大原则中的任何一个,不能通过传递性推测出来什么。


A happens-before B,定义1要求A执行结果对B可见,并且A操作的执行顺序在B操作之前,但与此同时利用定义中的第二条,A,B操作彼此不存在数据依赖性,两个操作的执行顺序对最终结果都不会产生影响,在不改变最终结果的前提下,允许A,B两个操作重排序,即happens-before关系并不代表了最终的执行顺序

As-If-Serial语义的介绍(面向处理器的语义规范)单线程场景下

不管怎么重排序(编译器和处理器为了提高并行度),单线程程序的执行结果不能被改变。编译器,runtime 和处理器都必须遵守as-if-serial语义。

为了遵守as-if-serial语义,编译器和处理器不会对存在数据依赖关系的操作做重排序,因为这种重排序会改变执行结果。但是,如果操作之间不存在数据依赖关系,这些操作可能被编译器和处理器重排序

到此,关于“Happens-Before原则和As-If-Serial语义是什么”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!

推荐阅读:
  1. happens-before和as-if-serial语义的示例分析
  2. 深入浅出了解happens-before原则

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

java

上一篇:HTML5 Web Sockets的介绍以及应用

下一篇:HTML DOM padding属性的定义和用法

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》