一、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. Lombok 注解简介

    Lombok @AllArgsConstructor /** * 生成一个包含所有属性的构造函数 */ @Target(ElementType.TYPE) @Retention(RetentionPo ...

  2. ubuntu通过windows下的ccproxy代理上网

    网上教程很多,需要注意的是将ubuntu的ip和windows的Ip设置到同一个网段,即子网掩码是1的对应的部分要相同.由于没有配置到同一个网段,折腾了我好久.

  3. Linux_进程管理&计划任务

    目录 目录 top打开Linux系统任务管理控制台 ps进程查询指令 kill进程关闭指令 一个小实验 一次性计划任务 周期性计划任务 top打开Linux系统任务管理控制台 快捷键: P M k q ...

  4. apache-httpd2.2编译安装

    1.下载源码包 wget http://mirrors.hust.edu.cn/apache/httpd-2.2.32.tar.gz2.解压源码包 tar -zxvf httpd-2.2.32.tar ...

  5. 你知道 Git 是如何做版本控制的吗?(转)

    总结:阅读这篇文章需要20分钟 本文是转载自 滴滴WebApp架构组 的一篇文章,文章讲解了神秘的.git目录下的一些文件,最终阐述了git是如何存储数据,及git分支的相关内容. git如何存储数据 ...

  6. 测开之路一百四十八:WTForms表单验证

    使用WTForms表单验证,可以在数据建模时就设置验证信息和错误提示 创建模型时,设置验证内容,如必填.格式.长度 from flask_wtf import Formfrom wtforms imp ...

  7. 基于python+requests的简单接口测试

    在进行接口测试时,我们可以使用已有的工具(如:jmeter)进行,也可以使用python+requests进行.以下为简单的接口测试模板: 一.提取常用变量,统一配置 新建一个config.py文件, ...

  8. Java ——多线程编程

    本节重点思维导图 多线程编程

  9. 使用Dockerfile制作镜像

    组成部分 基础镜像信息       FROM 维护者信息    MAINTAINER.LABEL 镜像操作指令       RUN.COPY.ADD.EXPOSE.WORKDIR.ONBUILD.US ...

  10. node.js中的 compression 中间件

    NodeJs——express启用gzip gzip是用于压缩,js.css等文件的压缩 具体方法如下: 先安装一个依赖 npm install compression --save 在项目的 app ...