Java并发(三)(1),上岸蚂蚁金服

happens-before


《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》

【docs.qq.com/doc/DSmxTbFJ1cmN1R2dB】 完整内容开源分享


happens-before是一种关系,在JMM中,如果一个操作执行的结果需要对另一个操作可见,那么这两个操作之间必须要存在happens-before关系,注意,这里的两个操作既可以是不同线程,也可以是同一个线程

那happens-before有什么规则了

  1. 程序顺序规则:一个线程中的每个操作,该线程中的任意后续动作都必须可以看到前面操作的结果,所以happens-before于该线程的任意后续动作

  2. 监视器锁规则:当一个锁解锁后,后面的加锁动作都要可以看到解锁动作,所以happens-before于随后对这个锁的加锁

  3. volatile变量规则:volatile实现了变量的线程可见性,所以对这个变量的操作都要被后续可见,所以happens-before于任意后续对这个volatile域的读

  4. 传递性:如果B可见A,即A可以happens-before于B,如果此时,C又可见B,即B可以happens-before于C,那么对于A和C,A可以happens-before于C

其实happens-before只是一个规则,抽象了JMM提供的内存可见性而已,也就是不用去认识透彻前面提到过的各种重排序,而happens-before的实现其实也就是JMM禁止了各种重排序

重排序


前面我们已经简单了解过重排序

重排序是指:编译器和处理器为了优化程序性能而对指令序列进行重新排序的一种手段,关键在于是为了优化性能,而且要注意,每个线程都会发生重排序,因为处理器每次执行都只是执行一个线程

数据依赖性

数据依赖性是指:有两个操作访问同一个变量,并且这些操作至少有一个为写操作,那么此时这两个操作就存在数据依赖性,也因此数据依赖性根据两个操作的顺序会分为三种

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

  • 读后写:读一个变量之后,再进行写入,注意这里是写入而不是修改,比如,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线程先执行)

在这里插入图片描述

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值