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的重排序,将

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

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

修改flag变量的操作提前或者延后了,B线程获取的flag变量可能为修改前的,也可能为修改后的

顺序一致性


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

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

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

举个栗子

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

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

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

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

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

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

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

Java并发(三),孔浩java视频百度云盘相关推荐

  1. 孔浩用的mysql工具_孔浩Java教学系列视频教程

    孔浩Java教学系列视频教程包含了孔浩老师目前为止所有JAVA相关的技术视频教程,有J2SE开发雇员管理系统.mysql使用.JAVA开发简单网上购物的系统.JAVA开发CMS系统.所有视频分8个类别 ...

  2. Java并发指南6:Java内存模型JMM总结

    本文转自 https://www.cnblogs.com/kukri/p/9109639.html 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库 ...

  3. java并发编程之4——Java锁分解锁分段技术

    转载自 java并发编程之4--Java锁分解锁分段技术 并发编程的所有问题,最后都转换成了,"有状态bean"的状态的同步与互斥修改问题.而最后提出的解决"有状态bea ...

  4. 孔浩java爱酷网_JAVA

    http://www.scalachina.com/ scala社区 http://blog.csdn.net/mapdigit/article/details/21878083 Scala教程 ht ...

  5. 孔浩老师 java 微信_孔浩老师JAVA WebService教程

    课程目录:01_webservice快速实例 02_wsimport的使用 03_wsdl和soap讲解(介入了tcpmon工具) 04_SOA的分析(纯属扯淡) 05_dtd讲解 06_schema ...

  6. 孔浩java爱酷网_spring mvc学习

    1.首先是环境的搭建 导入jar包,就把spring的所有jar导进去就好,再加上commons-logging.jar包导入 注意:这里仅仅导入还不行,还需要把jar包拖动到项目的lib目录中 2. ...

  7. 并发执行变成串行_大白话Java并发面试问题之Java 8如何优化CAS性能?

    专注于Java领域优质技术,欢迎关注 来自:石杉的架构笔记 一.前言 这篇文章给大家聊一下java并发包下的CAS相关的原子操作,以及Java 8如何改进和优化CAS操作的性能. 因为Atomic系列 ...

  8. 【Java并发编程 四】Java的进程与线程

    什么是进程?进程是程序的⼀次执⾏过程,是系统运⾏程序的基本单位,因此进程是动态的.系统运行和关闭⼀个程序即是⼀个进程从创建,运⾏到消亡的过程.在 Java 中,当我们启动 main 函数时其实就是启动 ...

  9. Java并发指南14:Java并发容器ConcurrentSkipListMap与CopyOnWriteArrayList

    原文出处http://cmsblogs.com/ 『chenssy』 到目前为止,我们在Java世界里看到了两种实现key-value的数据结构:Hash.TreeMap,这两种数据结构各自都有着优缺 ...

  10. Java并发指南17:Java常见多线程面试题及答案

    Java多线程面试题及答案(2020版) 前言 个人珍藏的80道Java多线程/并发经典面试题,因为篇幅太长,现在先给出1-10的答案解析哈,后面一起完善~ 1. synchronized的实现原理以 ...

最新文章

  1. [喵咪的Liunx(1)]计划任务队列脚本后台进程Supervisor帮你搞定
  2. Python 闭包详解
  3. html运行c代码大全,html特效代码大全
  4. sess.run(tf.global_variables_initializer()) 做了什么?
  5. 【二分】【最小生成树】公路修建问题(P2323)
  6. 程序员惊魂 12 小时:“���”引发线上事故
  7. android.mk 编译32位_C/C++初学者常见编译错误及其解决办法
  8. [转] 深入浅出oracle锁---原理篇
  9. github入门到上传本地项目(转)
  10. java中reg=new,JavaScript replace new RegExp使用介绍
  11. java2实用教程 第四版 上机实践4代码_Java2实用教程实验指导模版代码
  12. 日本专利检索地址和专利号码问题
  13. MIUI11线刷包精简
  14. C# 单例模式的五种写法
  15. A-priori算法的简单实现
  16. 日期计算器输入天数计算日期_如何在Windows计算器中执行日期计算
  17. 企业邮箱怎么弄企业邮箱是什么邮箱求一个企业邮箱账号
  18. C# Dictionary源码解析
  19. 宣州谢朓楼饯别校书叔云
  20. 微信小程序map中polyline的坑

热门文章

  1. Axure RP9 的元件库
  2. 我的世界java种子 要塞,《我的世界》你绝对没见过的稀奇种子,恐龙骨架出现在要塞...
  3. 帆软帮助文档_聚焦商业智能主赛道,帆软如何取得里程碑式突破
  4. 279. 完全平方数
  5. LinkedIn第三方登录
  6. vm虚拟机安装gho系统_虚拟机怎么安装gho系统
  7. python点云可视化
  8. USB转TTL、USB转串口、USB转RS232的区别
  9. 规划设计计算机配置,平面设计电脑配置
  10. Matlab调用系统命令行利用Internet Download Manager(IDM)实现批量下载