1、背景问题

在讲happens-before之前,先引入一个例子:

假定我们有已经被初始化的变量:

int counter = 0;
这个 counter 变量被两个线程所共有,也就是说线程A和线程B都可以获取或者更改counter的值。 这里我们假设线程A要增加counter的值:
counter++;

然后,线程B打印counter的值
System.out.println(counter);

如果上面两条语句被同一个线程执行,我们可以肯定的说打印出来的值是1. 但是如果这两条语句分别被两个线程执行,其打印出来的值却可能是0(如果不知道为何为0,请参考我的另一篇文章java多线程之内存可见性),
因为这里并没有任何保证说线程A对counter的修改一定对线程B所见。除非我们在两条语句之间建立起 happens-before的关系。

2、happens-before关系

什么是happens-before关系? 这个关系其实就是一个保证而已,那么保证什么呢?它保证一条语句对内存的写操作对另一条语句是可见的。换句话说,如果写操作A和读操作B存在happens-before这种关系,那么写操作在结束以后都操作才能开始。

下面是Java内存模型中的八条可保证happen—before的规则,它们无需任何同步器协助就已经存在,可以在编码中直接使用。
1、程序次序规则:在一个单独的线程中,按照程序代码的执行流顺序,(时间上)先执行的操作happen—before(时间上)后执行的操作。
2、管理锁定规则:一个unlock操作happen—before后面(时间上的先后顺序,下同)对同一个锁的lock操作。
3、volatile变量规则:对一个volatile变量的写操作happen—before后面对该变量的读操作。
4、线程启动规则:Thread对象的start()方法happen—before此线程的每一个动作。
5、线程终止规则:线程的所有操作都happen—before对此线程的终止检测,可以通过Thread.join()方法结束、Thread.isAlive()的返回值等手段检测到线程已经终止执行。
6、线程中断规则:对线程interrupt()方法的调用happen—before发生于被中断线程的代码检测到中断时事件的发生。
7、对象终结规则:一个对象的初始化完成(构造函数执行结束)happen—before它的finalize()方法的开始。
8、传递性:如果操作A happen—before操作B,操作B happen—before操作C,那么可以得出A happen—before操作C。

这里的八个规则除了第三个以外都容易理解。所以专门讲一下volatile变量规则。

1、 对volatile变量执行写操作时,会在写操作后加入一条store屏障指令

2、 对volatile变量执行读操作时,会在读操作前加入一条load屏障指令。

通俗得讲,volatile变量在每次被线程访问时,都强迫从主内存中读该变量的值,而当该变量发生变化时,又会强迫将最新的值刷新到主内存。这样任何时刻,不同的线程总是能够看到该变量的最新值。

如果你不能够理解,我们可以采取一种极端的思维方式:如果有两个线程的话,对于一个普通变量,在java内存模型中它是有三个拷贝的,一个在主内存,另外两个在线程的工作内存里。如果刷新不及时,那么就可能导致两个工作内存中的变量值不一致。但是对于volatile变量,你完全可以假定其只有一份而且唯一一份拷贝在主内存中发生,所以当两个线程想对volatile变量进行更改或者读取的时候,总是得等其中一个线程完成以后才行。

参考:

https://docs.oracle.com/javase/tutorial/essential/concurrency/memconsist.html

https://en.wikipedia.org/wiki/Happened-before

http://blog.csdn.net/ns_code/article/details/17348313

https://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.4.5

 

java多线程之happens-before的更多相关文章

  1. Java多线程之ConcurrentSkipListMap深入分析(转)

    Java多线程之ConcurrentSkipListMap深入分析   一.前言 concurrentHashMap与ConcurrentSkipListMap性能测试 在4线程1.6万数据的条件下, ...

  2. JAVA多线程之wait/notify

    本文主要学习JAVA多线程中的 wait()方法 与 notify()/notifyAll()方法的用法. ①wait() 与 notify/notifyAll 方法必须在同步代码块中使用 ②wait ...

  3. JAVA多线程之volatile 与 synchronized 的比较

    一,volatile关键字的可见性 要想理解volatile关键字,得先了解下JAVA的内存模型,Java内存模型的抽象示意图如下: 从图中可以看出: ①每个线程都有一个自己的本地内存空间--线程栈空 ...

  4. java多线程之yield,join,wait,sleep的区别

    Java多线程之yield,join,wait,sleep的区别 Java多线程中,经常会遇到yield,join,wait和sleep方法.容易混淆他们的功能及作用.自己仔细研究了下,他们主要的区别 ...

  5. Java多线程之Runnable与Thread

    Java多线程之Thread与Runnable 一.Thread VS Runnable 在java中可有两种方式实现多线程,一种是继承Thread类,一种是实现Runnable接口:Thread类和 ...

  6. JAVA多线程之UncaughtExceptionHandler——处理非正常的线程中止

    JAVA多线程之UncaughtExceptionHandler——处理非正常的线程中止 背景 当单线程的程序发生一个未捕获的异常时我们可以采用try....catch进行异常的捕获,但是在多线程环境 ...

  7. java多线程之wait和notify协作,生产者和消费者

    这篇直接贴代码了 package cn.javaBase.study_thread1; class Source { public static int num = 0; //假设这是馒头的数量 } ...

  8. Java——多线程之Lock锁

    Java多线系列文章是Java多线程的详解介绍,对多线程还不熟悉的同学可以先去看一下我的这篇博客Java基础系列3:多线程超详细总结,这篇博客从宏观层面介绍了多线程的整体概况,接下来的几篇文章是对多线 ...

  9. java多线程之:深入JVM锁机制2-Lock (转载)

    前文(深入JVM锁机制-synchronized)分析了JVM中的synchronized实现,本文继续分析JVM中的另一种锁Lock的实现.与synchronized不同的是,Lock完全用Java ...

  10. Java多线程之Callable接口与Runnable的实现以及选择

    通过实现Runnable接口的实现 package Thread; import java.util.concurrent.ExecutorService;import java.util.concu ...

随机推荐

  1. Struts2 学习笔记——struts.xml文件之Bean的配置

    Struts2的大部分核心组件不是以硬编码的形式写在代码中,而是通过自身的IoC容器来管理的. Struts2以可配置的形式来管理核心组件,所以开发者可以很容易的扩展框架的核心组件.当开发者需要扩展或 ...

  2. Web常用方法

    1.返回一个json格式报文 /**     * 返回json格式字符串或普通字符串     *      * @param jsonString     */    protected void w ...

  3. androd 获得wifi列表

    AndroidManifest.xml <?xml version="1.0" encoding="utf-8"?> <manifest xm ...

  4. 【Linux】CentOS7 上使用yum安装和卸载软件【yum安装wine举例】

    关于yum的相关解释,请 man yum 自行查看. 配置常用源:http://www.cnblogs.com/sxdcgaq8080/p/7516186.html yum的使用类似于在windows ...

  5. ora01940 无法删除当前连接的用户

    我用system这个用户登录oracle,想删除掉一个自己创建的用户user,在网上找到的方法都是说先查找到该用户连接的会话select username,sid,serial# from v$ses ...

  6. zabbix自定义监控项一

    1.在agent端配置 1.1 添加自定义监控项 zabbix中监控项叫做item,监控项的取值方法叫做key item: Items是从agnet主机里面获取的所有数据.通常情况下我叫itme为监控 ...

  7. OC第五课

    主要内容:字典.集合.数组排序 一.字典 演示样例: name : @" 张三 " .sex:@" 男 " ; age :@" 21 " ; ...

  8. ImageSwitcher (图像切换器,显示图片)

    ImageSwitcher继承了ViewSwitcher,主要在切换图片时加入动画效果 使用方法: 1.为ImageSwitcher提供一个ViewFactory,该ViewFactory生成的Vie ...

  9. PS如何拉倒影效果

    1 复制图形(一般是文字)并垂直翻转得到倒影的初步样子(最好倾斜一下,看起来逼真一些)就像下面的迅雷的样子.记住要栅格化文字. 2 用魔棒工具抠除原来的颜色,只剩下空的选区.   3 拉渐变

  10. iOS开发:解决UIScrollView不滚动的问题

    照着书上的Demo(iOS 5.0的教程),在- (void)viewDidLoad里设置scrollView的contentsize,让它大于屏幕的高度,却发现在模拟器中没用,还是不能滚.经过 一翻 ...