java并发学习--第九章 指令重排序

一、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关键字来解决。

  

  

posted @ 2019-11-02 15:05  想去天空的猫  阅读(1369)  评论(0编辑  收藏  举报