一、happns-before

  happns-before是学习指令重排序前的一个必须了解的知识点,他的作用主要是就是用来判断代码的执行顺序。

  1.定义

  happens-before是用来指定两个操作之间的执行顺序。提供跨线程的内存可见性。

  在java内存模型中,如果一个操作执行的结果需要对另一个操作可见,那么这两个操作之间必然存在happens-before关系

  2.happens-before规则

  a.程序顺序规则

  单线程中的每个操作,总是前一个操作happens-before于该线程中的任意后续操作。

  简单的说,这个规则就是代码按照顺序执行。

  b.监视器规则

  对一个锁的解锁,总是happens-before于随后对这个锁的加锁。

  这句话可以理解成对于同一把锁,释放与获取是线程可见的;释放锁的操作总是happens-before于获取锁的操作。

  c.volatile变量规则

  对一个volatile域的写总是happens-before于任意后续对这个volatile域的读。

  就是说被volatile修饰的变量,在线程中是是可见的。

  d.传递性

  这个规则与程序性规则相识:有A、B、C三变量,如果根据程序性规则:

    A变量 happens-before B变量,

    B变量 happens-before C变量,

    则必然有

    A变量 happens-before C变量。

  f.start规则

  这个规则是在多线程场景中会经常出现的:A线程中调用了B线程,那么A线程happens-before于B线程。

  或者说A线程的结果对B线程是可见的(结果必须在调用B线程前就已经出现)。

  g.join规则

  多线程场景中,如果有线程使用了join方法,那么join的线程一点是happens-before于调用的线程。

二、指令重排序

  了解过happens-before后,终于可以进入本结的主题了指令重排序。

  1.定义

  我们知道jvm运行的是java文件编译后的字节码指令,编译器为了优化程序的性能,会重新对字节码指令排序,虽然会重排序,但是指令重排序运行的结果一定是正常的。

  2.数据的依赖性

  能够进行指令重排序的地方,就是看这个段代码的数据依赖性,有三种情况是不能够进行指令重排序的:

  ①对某个对象或者变量,先进行赋值再读这个对象的值(写后读)

  ②对某个对象或者变量,先读这个对象的值再对这个对象赋值(读后写)

  ③对某个对象或者变量,先后进行了两次赋值(写后写)

  如果对这三种情况进行指令重排序的话,获得的结果一定是错误的。所以规定在这三种情况中,是不能进行指令重排序。

  3.指令重排序所带来的影响

  指令重排序一共分为两种情况:

  a.编译器重排序

  b.处理器重排序(这个必须是在多个CPU情况下才会发生)

  指令重排序在单线程中对我们程序的帮助一定是正向的,它能够很好的优化我们程序的性能。但是在多线程情况下,就不一定了,但是出现指令重排序情况导致线程安全性问题的情况都是很少见的,就算出现也是很难去发现的。最简单的例子:双检查锁单例模式。如果出现了由于指令重排序造成的线程安全性问题,就可以使用volatile关键字来解决。

  

  

java并发学习--第九章 指令重排序的更多相关文章

  1. Java并发(三):重排序

    在执行程序时为了提高性能,提高并行度,编译器和处理器常常会对指令做重排序.重排序分三种类型: 编译器优化的重排序.编译器在不改变单线程程序语义的前提下,可以重新安排语句的执行顺序. 指令级并行的重排序 ...

  2. Java并发编程的艺术(二)——重排序

    当我们写一个单线程程序时,总以为计算机会一行行地运行代码,然而事实并非如此. 什么是重排序? 重排序指的是编译器.处理器在不改变程序执行结果的前提下,重新排列指令的执行顺序,以达到最佳的运行效率. 重 ...

  3. java并发学习--第一章 线程的创建

    所谓的并发就是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程序在处理机上运行.所以我们看似几个线程在同时进行,其实在操作系统中 ...

  4. java并发学习--第二章 spring boot实现线程的创建

    除了之前介绍的创建线程方式外,spring boot为我们了提供一套完整的线程创建方式,其中包括了:线程.线程池.线程的监控. 一.使用spring boot提供的方法创建线程与线程池 1.首先在sp ...

  5. Java的多线程机制系列:不得不提的volatile及指令重排序(happen-before)

    一.不得不提的volatile volatile是个很老的关键字,几乎伴随着JDK的诞生而诞生,我们都知道这个关键字,但又不太清楚什么时候会使用它:我们在JDK及开源框架中随处可见这个关键字,但并发专 ...

  6. Java的多线程机制系列:(四)不得不提的volatile及指令重排序(happen-before)

    一.不得不提的volatile volatile是个很老的关键字,几乎伴随着JDK的诞生而诞生,我们都知道这个关键字,但又不太清楚什么时候会使用它:我们在JDK及开源框架中随处可见这个关键字,但并发专 ...

  7. java指令重排序的问题

    转载自于:http://my.oschina.net/004/blog/222069?fromerr=ER2mp62C 指令重排序是个比较复杂.觉得有些不可思议的问题,同样是先以例子开头(建议大家跑下 ...

  8. JVM学习(八)指令重排序

    一.数据依赖性 在学习JVM的指令重排序之前,我们先了解一下什么是数据依赖性: 编译器和处理器在处理具体的指令时,可能会对操作进行重排序来提高执行性能[多条指令并行执行,所以提升性能的同时也可能会导致 ...

  9. 不得不提的volatile及指令重排序(happen-before)

    微信公众号[程序员江湖] 作者黄小斜,斜杠青年,某985硕士,阿里 Java 研发工程师,于 2018 年秋招拿到 BAT 头条.网易.滴滴等 8 个大厂 offer,目前致力于分享这几年的学习经验. ...

随机推荐

  1. Nor Flash芯片特性分析

    Nor Flash是Intel在1988年推出的非易失闪存芯片,可随机读取,擦写时间长,可以擦写1~100W次,支持XIP(eXecute In Place). 本文以JS28F512M29EWH为例 ...

  2. 洛谷 P3865 ST表

    ST表 ST表的功能很简单 它是解决RMQ问题(区间最值问题)的一种强有力的工具 它可以做到O(nlogn)预处理,O(1)查询最值 是一种处理静态区间可重复计算问题的数据结构,一般也就求求最大最小值 ...

  3. C语言字符数组详解

    字符串的存储方式有字符数组和字符指针,我们先来看看字符数组. 因为字符串是由多个字符组成的序列,所以要想存储一个字符串,可以先把它拆成一个个字符,然后分别对这些字符进行存储,即通过字符数组存储.字符数 ...

  4. EDM杂谈:第一个屏幕的定义和特点

    在EDM营销中,经常会碰到第一个屏幕这个概念.这是什么意思呢?博主跟大家介绍一下. 图一:博文配图 这个主要是指用户在打开邮件时不需要滚动屏幕就可以看到的邮件内容.因为用户第一眼就可以看到,因此这部分 ...

  5. c++ 加载资源文件

    int _tmain(int argc, _TCHAR* argv[]) { HRSRC hRsrc = FindResource(NULL, MAKEINTRESOURCE(IDR_DATA1), ...

  6. 【Qt开发】设置Qt应用程序图标

    [Qt开发]设置Qt应用程序图标 标签:[Qt开发] 首先,准备一个图标,例如:zx.ico,并新建一个文本文档,在里面添加一行: IDI_ICON1 ICON DISCARDABLE"zx ...

  7. /proc/cpuinfo 查看cpu信息

    /proc/cpuinfo 查看cpu信息 如类型.厂家.型号

  8. Spark-Core RDD行动算子

    1.reduce(func) 通过func函数聚集RDD 中的所有元素,先聚合分区内数据,再聚合分区间数据. scala> val rdd1 = sc.parallelize(1 to 100) ...

  9. javascript中的继承-寄生组合式继承

    前文说过,组合继承是javascript最常用的继承模式,不过,它也有自己的不足:组合继承无论在什么情况下,都会调用两次父类构造函数,一次是在创建子类原型的时候,另一次是在子类构造函数内部.子类最终会 ...

  10. phpstudy添加PHP

    想在phpstudy2018里面增加一个php版本,操作如下: 一.下载php-7.2.19-ts文件,解压缩,放在相应的目录下: 二.修改Apache的配置文件1.修改httpd.conf 配置,D ...