并发编程-锁的那些事儿【三:发行发生原则-Happens-Before】

前言

经过前几篇Java内存模型与三大特性了解后,还需要掌握另一中比较苦涩难懂的一块规则:发行发生原则。 如果Java中的有序性,均通过volatile synchronize等方式控制,那么有些场景下有些代码会有些繁琐。 但在开发中,我们并没有这种感觉,正是这个 发行发生原则 在 默默起作用;这个规则十分重要,数据是否存在竞争关系,线程是否安全,都是依靠这个规则来判定。 它真正要表达的是: 前面一个操作的结果对后续操作是可见的

Happens-Before规则详解

Java内存中规定一些默认的法则存在,即使没有同步器的存在,也可以在编码中直接使用,假如两个操作直接不存在一下关系,或者无法从下述规则推导出来,那么就说明没有顺序保证,虚拟机就可以对其指令重排;

  • 1、程序次序规则:**在一个线程内按照代码的的顺序,在前的代码Happens-Before任意后面的代码; 例如: public void writer() { a = 1; b = true; c = “1”; …} a变量在b,c之前赋值,那么a变量一定对b,c,任意的操作具备可见。

  • 2、管程锁定规则:**无论是在单线程环境还是多线程环境,对于同一个锁来说,一个线程对这个锁解锁之后,另一个线程获取了这个锁都能看到前一个线程的操作结果!(管程是一种通用的同步原语,synchronized就是管程的实现)

  • 3、volatile变量规则:**在一个线程中对一个volatile变量进行写操作,那么这个写操作的结果一定对其他读线程可见。

  • 4、线程启动规则:**在主线程A执行过程中,启动子线程B,那么线程A在启动子线程B之前对共享变量的修改结果对线程B可见。 简单来说:线程 A 调用线程 B 的 start() 方法(即在线程 A 中启动线程 B),那 么该 start() 操作 Happens-Before 于线程 B 中的任意操作

  • 5、线程终止规则:**在主线程A执行过程中,子线程B终止,那么线程B在终止之前对共享变量的修改结果在线程A中可见。

  • 6、线程中断规则:**对线程interrupt()方法的调用先行发生于被中断线程代码检测到中断事件的发生,可以通过Thread.interrupted()检测到是否发生中断。

  • 7、传递规则:** happens-before原则具有传递性,即A happens-before B , B happens-before C,那么A happens-before C。 借助 规则1和3来说明:
    基于规则1调整下代码:

volatile boolean b = false;  
public void writer() { a = 1;  b = true;}
public void read() { if (b) { 输出a } }

1. a = 1 B-F b = true
2. writer()的b = true B-F read()的b
3. 线程1 执行read()方法的同时,线程1执行writer()方法,那么此时a = 1对线程1也是可见的,也就是此时输出的a == 1
  • 8、对象终结规则:**这个也简单的,就是一个对象的初始化的完成,也就是构造函数执行的结束一定 happens-before它的finalize()方法。

总结

Happens-Before为了保障可见性,最终要表达的思想:前面一个操作的结果对后续操作是可见的,而这个规则则是各个线程之间的规范,约束 了编译器的优化行为,虽允许编译器优化,但是要求编译器优化后一定遵守规则;

你可能感兴趣的:(并发编程)