Java并发(三):重排序与内存一致性

本文讨论了编程中的数据依赖性和as-if-serial语义,强调了单线程环境下重排序的控制以及在多线程中可能出现的语义错误。重点讲解了控制依赖、重排序对多线程一致性的影响,以及JMM中顺序一致性实现的挑战。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 写后读:写入一个变量之后,再进行读取

  • 读后写:读一个变量之后,再进行写入,注意这里是写入而不是修改,比如,a = b;b = 1就是一个读后写

  • 写后写:写一个变量之后,再重新进行写入

上面三种数据依赖性,只要发生操作的重排序,程序的执行结果都会被改变,而前面已经提到过,编译器和处理器是会对操作进行重排序的,所以为了防止执行结果发生改变,编译器和处理器要辨别出操作是否存在数据依赖性,如果存在数据依赖性是不会进行重排序的,但这种自动禁止重排序操作仅仅出现在单线程和单处理器,也就是仅仅只会考虑单线程和单处理器的数据依赖性,对于不同线程和不同处理器之间的数据依赖性是不会被考虑的

as-if-serial语义

as-if-serial语义是指:不管怎么进行重排序,程序的执行结果都不能改变,当然这也只是针对单线程,也就是单线程的执行结果都不能改变,不保证多线程是否发生了改变

举个栗子

double pi = 3.14; //A操作

double r = 1; //B操作

double area = pi * r * r; //C操作

在上面的三个操作,产生数据依赖性的有A与C、B与C,而且产生的都是写后写数据依赖性,那么A与B是没有数据依赖性的,这两个操作发生重排序是不会违反as-if-serial语义,所以这两个操作允许发生重排序,但是C操作就不可以随便发生重排序了,必须要满足A-happensbefore-C与B-happensbefore-C

总的来说,as-if-serial语义是将单线程程序保护了起来,不用去考虑重排序导致的问题,让开发者可以认为程序就是按顺序执行的,重排序不会干扰

as-if-serial也允许对存在控制依赖的操作进行重排序

控制依赖就是指:逻辑判断操作,即if那些判断语句,那些判断语句也是一个操作,具体来说就是,允许先执行if里面的代码块,然后再判断if的条件是否为True或者False

因为控制依赖会影响指令序列执行的并行度,本可以执行多个命令的,偏偏要先去执行判断命令,等判断完再去执行其他命令,这会降低了指令序列的并行度,所以干脆就一起并行执行,判断条件后再考虑结果是否保留即可,即允许发生重排序

重排序对多线程的影响

重排序是针对单线程进行的,单线程发生重排序是没有任何问题的,因为有着as-if-serial语义的保证,但是多线程各自线程发生重排序,组合起来就会产生多线程的语义错误,把程序的执行结果给改变

举个栗子

假如A线程修改了一个flag变量,而B线程去获取这个flag变量,那么由于A的重排序,将修改flag变量的操作提前或者延后了,B线程获取的flag变量可能为修改前的,也可能为修改后的

顺序一致性


程序一致性是用来形容多线程同步执行的,规则如下

  • 一个线程中的所有操作必须按照程序的顺序来执行

  • 所有线程都只能看到一个单一的操作执行顺序,不管是同步还是不同步,每个操作都必须是原子执行且立刻对所有线程可见

举个栗子

有一个线程A,拥有三个操作,A1、A2、A3;另外一个线程B,也有三个操作,B1、B2、B3

那么在同步的时候,这2个线程共6个操作的执行顺序如下所示(假设A线程先执行)

在这里插入图片描述

可以看见,每个线程的三个操作都必须是按顺序执行的

下面是不同步的时候,这2个线程共6个操作的执行顺序可能会有多种,下面只是其中一种情况

在这里插入图片描述

可以看到,即使是不同步的情况下,虽然整体上是无序的,但顺序一致性保证每个线程里面的操作是顺序执行的

实现顺序一致性的前提保证是每个操作必须立即对任意线程可见,就这样就可以后面的操作不会受影响,可以立即执行

但在JMM中,并不能实现顺序一致性,每个操作不是立即对任意线程可见的,前面提到过,每个线程都有自己的缓存,操作是先对缓存操作,然后再对主存操作的,所以对于不同步的多线程来说,不但整体的执行顺序是乱序的,而且所有线程看到的操作执行顺序也可能不一致,因为可能会发生重排序;如果是同步的话,也可能不是一致的,因为重排序,不过由于as-if-serial语义,外界可以视为顺序一致的

下面就来分析一下JMM同步和不同步情况下与顺序一致性的区别

同步程序

在顺序一致性中,所有操作完全按程序的顺序串行执行的,而在JMM中,对于临界区的代码是可能会发生重排序的,具体一点就是加锁的代码会发生重排序

这种重排序可以提高执行效率,而且没有改变执行的结果

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

总结

三个工作日收到了offer,头条面试体验还是很棒的,这次的头条面试好像每面技术都问了我算法,然后就是中间件、MySQL、Redis、Kafka、网络等等。

  • 第一个是算法

关于算法,我觉得最好的是刷题,作死的刷的,多做多练习,加上自己的理解,还是比较容易拿下的。

而且,我貌似是将《算法刷题LeetCode中文版》、《算法的乐趣》大概都过了一遍,尤其是这本

《算法刷题LeetCode中文版》总共有15个章节:编程技巧、线性表、字符串、栈和队列、树、排序、查找、暴力枚举法、广度优先搜索、深度优先搜索、分治法、贪心法、动态规划、图、细节实现题

最新出炉,头条三面技术四面HR,看我如何一步一步攻克面试官?

《算法的乐趣》共有23个章节:

最新出炉,头条三面技术四面HR,看我如何一步一步攻克面试官?

最新出炉,头条三面技术四面HR,看我如何一步一步攻克面试官?

  • 第二个是Redis、MySQL、kafka(给大家看下我都有哪些复习笔记)

基本上都是面试真题解析、笔记和学习大纲图,感觉复习也就需要这些吧(个人意见)

最新出炉,头条三面技术四面HR,看我如何一步一步攻克面试官?

  • 第三个是网络(给大家看一本我之前得到的《JAVA核心知识整理》包括30个章节分类,这本283页的JAVA核心知识整理还是很不错的,一次性总结了30个分享的大知识点)

最新出炉,头条三面技术四面HR,看我如何一步一步攻克面试官?

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
一次性总结了30个分享的大知识点)**

[外链图片转存中…(img-3pYpLCGB-1712611397486)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值