美文网首页Java系统架构师
重排序和数据依赖性

重排序和数据依赖性

作者: 猿灯塔 | 来源:发表于2020-04-16 09:58 被阅读0次

原创申明:本文由公众号【猿灯塔】原创,转载请说明出处标注

今天呢!灯塔君跟大家讲:

什么是重排序?

重排序是指编译器和处理器为了优化程序性能对指令序列进行重新排序的一种手段。Java内存模型中,允许编译器和处理器对指令进行重排序,但是重排序可以保证最终执行的结果是与程序顺序执行的结果一致,并且只会对不存在数据依赖性的指令进行重排序,这个重排序在单线程下对最终执行结果是没有影响的,但是在多线程下就会存在问题。

1int a =1;(1)

2int b =2;(2)

3int c= a + b;(3)

如上c的值依赖a和b的值,所以重排序后能够保证(3)的操作在(2)(1)之后,但是(1)(2)谁先执行就不一定 了,这在单线程下不会存在问题,因为并不影响最终结果。

1classRecorderExample{

2int a =0;

3boolean flag =false;

4public void write(){

5a =1;//1

6flag =true;//2

7}

8public void read(){

9if(!flag){//3

10a =2;//4

11}

12}

13}

有两个线程,线程A首先执行write()方法,线程B首先执行read()方法。

JMM中可能的执行时序为:

而编译器可以对操作1和操作2进行重排序

得到的执行时序为:

一个多线程的例子:

1publicclassTestCP{

2privatestaticintnum =0;

3privatestaticbooleanready =false;

4publicstaticclassReadThreadextendsThread{

5publicvoidrun(){

6while(!Thread.currentThread().isInterrupted()){

7if(ready){//(1) 

8System.out.println(num+num);//(2)如代码由于(1)(2)(3)(4) 之间不存在依赖,所以写线程(3)(4)可能被重排序为先执行(4)在执行(3),那么 

9执行(4)后,读线程可能已经执行了(1)操作,并且在(3)执行前开始执行(2)操作,这时候打印 

10结果为0而不是4. 

11改变程序执行结果的直接原因是重排序,而根本原因是未正确同步。 

12如果程序是正确同步的,程序的执行将具有顺序一致性。即:正确同步程序的执行结果与顺序一致性内 

13存模型的执行结果相同。 

14注意:这里的同步是广义的同步,包括同步原语(synchronized,volatile,fifinal)的正确使用。 

15从源代码到最终实际执行的指令序列,会分别经历以下三中排序 

162、数据依赖性 

17如果两个操作访问同一个变量,且这两个操作中有一个为写操作,此时这两个操作之间就存在数据依赖 

18性。数据依赖分为下列3种类型,如下图所示 19}

20System.out.println("read thread...."); 

21} 

22} 

23}

24public static class Writethread extends Thread { 

25public void run() { 

26num = 2;//(3) 

27ready = true;//(4) 

28System.out.println("writeThread set over..."); 

29} 

30}

31public static void main(String[] args) throws InterruptedException { 

32ReadThread rt = new ReadThread(); 

33rt.start(); 

34Writethread wt = new Writethread(); 

35wt.start(); 

36Thread.sleep(10); 

37rt.interrupt(); 

38System.out.println("main exit"); 

39} 

40}

如代码由于(1)(2)(3)(4)之间不存在依赖,所以写线程(3)(4)可能被重排序为先执行(4)在执行(3)那么执行(4)后,读线程可能已经执行了(1)操作,并且在(3)执行前开始执行(2)操作,这时候打印结果为0而不是4。

改变程序执行结果的直接原因是重排序,而根本原因是未正确同步。

如果程序是正确同步的,程序的执行将具有顺序一致性。即:正确同步程序的执行结果与顺序一致性内存模型的执行结果相同,注意:这里的同步是广义的同步,包括同步原语(synchronized,volatile,fifinal)的正确使用,从源代码到最终实际执行的指令序列,会分别经历以下三中排。

数据依赖性

如果两个操作访问同一个变量,且这两个操作中有一个为写操作,此时这两个操作之间就存在数据依赖性。

数据依赖分为下列3种类型如下图所示:

上面3种情况,只要重排序两个操作的执行顺序,程序的执行结果就会被改变。前面提到过编译器和处理器可能会对操作做重排序。编译器和处理器在重排序时,会遵守数据依赖性编译器和处理器不会改变存在数据依赖关系的两个操作的执行顺序。这里所说的数据依赖性仅针对单个处理器中执行的指令序列和单个线程中执行的操作,不同处理器之间和不同线程之间的数据依赖性不被编译器和处理器考虑。

365天干货不断,可以微信搜索「 猿灯塔」第一时间阅读,回复【资料】【面试】【简历】有我准备的一线大厂面试资料和简历模板

相关文章

  • Java指令重排序

    Java指令重排序Java内存模型允许编译器和处理器对指令重排序以提高运行性能,并且只会对不存在数据依赖性的指令重...

  • JMM内存模型之重排序

    重排序是指编译器和处理器为了优化程序性能而对指令序列进行重新排序的一种手段。 1. 数据依赖性 如果两个操作访问同...

  • 重排序和数据依赖性

    原创申明:本文由公众号【猿灯塔】原创,转载请说明出处标注 今天呢!灯塔君跟大家讲: 什么是重排序? 重排序是指编译...

  • R语言-09去重和排序

    去重和排序

  • Java内存模型-指令重排序&顺序一致性

    章节目录 1.重排序定义 2.数据依赖性 3.as-if-serial语义 4.程序顺序规则 5.JMM 参考 顺...

  • 排序算法总结

    排序算法 排序算法可以分为内部排序和外部排序 内部排序:数据记录在内存中进行排序。 外部排序:排序的数据很大,排序...

  • 利用R进行数据操作(基础知识篇)

    基本数据管理 目标: 操作日期和缺失值 熟悉数据类型的转换 变量的创建和重编码 数据集的排序、合并与取子集 选入和...

  • 常见的排序算法

    概述 排序分为内部排序和外部排序: 内部排序:数据记录在内存中进行排序 外部排序:排序的数据很大,一次不能容纳全部...

  • 几种常用的排序算法 回顾

    0. 概述 排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一...

  • Python经典排序算法

    排序:内部和外部 内部排序:数据记录在内存中进行排序。外部排序:排序的数据很大,一次不能容纳全部的排序记录,在排序...

网友评论

    本文标题:重排序和数据依赖性

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