happens-before(关键)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/HNUST_LIZEMING/article/details/88370457

在理论层次上分析,只要保证一下三点就可以保证多线程之间正确的同步。;

  1. 可见性:一个线程对主内存的修改可以及时的被其他线程观察到。
  2. 有序性:一个线程观察其他线程中的指令执行顺序,由于指令 重排序的存在,该观察结果一般杂乱无序。
  3. 原子性:提供了互斥访问。

冲突访问 对同一个共享字段或数组元素存在两个访问(读或写),且至少有一个访问是写操作,就称作有冲突。当程序包含两个没有被 happens-before 关系排序的冲突访问时,就称存在数据争用。(如果是被 happens-before 关系排序,那么编译器 处理器就会禁止相对应的重排序  并且通过hb规则告知程序员正确编写规则(这些处理就是不会改变程序结果的重排序 但是也是hb要求禁止的重排序,只不过这些约束交给程序员执行 非编译器 处理器执行,此结果的好处就是减少对处理器 以及编译器的约束))

同步加锁是在数据争用使用,确保数据正确性的一种手段,如果一个程序中不存在共享变量的话,就是存在可见性问题。不需用同步的手段保证正确性。

happens-before属于JMM一部分

1)理论上 程序员希望内存模型易于理解,易于编程。程序员希望的是强内存模型。

2)现实上,编译器 处理器希望内存模型希望其约束越少越好,希望的是一个弱内存模型。

JMM把happens-before禁止的指令分为两种:

1.会改变执行结果的指令重排序。

2.不会改变执行结果的指令重排序。

这里所指的执行结果是:多线程或者是单线程指令按照顺序一致性内存模型执行的结果(理想)。

有些内存可见性保证并不一定是真实存在的,例如A-->C B-->C A-->B。

JMM对编译器 处理器的约束已经是尽可能少的了,只要不影响程序执行结果,你想怎么优化就怎么优化。

happens-before定义

指定两个操作之间的执行顺序,这两个操作可以是单线程之内,也可以是不同线程之间的,通过happens-before保证提供跨线程的内存可见性。

1. 如果一个操作happens-before另一个操作,那么第一个操作的执行结果将对第二个操作可见,而且第一个操作的执行顺序排在第二个操作之前。 
2. 两个操作之间存在happens-before关系,并不意味着一定要按照happens-before原则制定的顺序来执行。如果重排序之后的执行结果与按照happens-before关系来执行的结果一致,那么这种重排序并不非法。例如A-->C B-->C A-->B。

下面是happens-before原则规则:

  1. 程序顺序规则:一个线程内,按照代码顺序,书写在前面的操作先行发生于书写在后面的操作;
  2. 锁定规则:一个unLock操作先行发生于后面对同一个锁额lock操作;
  3. volatile变量规则:对一个变量的写操作先行发生于后面对这个变量的读操作;
  4. 传递规则:如果操作A先行发生于操作B,而操作B又先行发生于操作C,则可以得出操作A先行发生于操作C;
  5. 线程启动规则:Thread对象的start()方法先行发生于此线程的每个一个动作;
  6. 线程中断规则:对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生;
  7. 线程终结规则:线程中所有的操作都先行发生于线程的终止检测,我们可以通过Thread.join()方法结束、Thread.isAlive()的返回值手段检测到线程已经终止执行;
  8. 对象终结规则:一个对象的初始化完成先行发生于他的finalize()方法的开始;

程序顺序规则:一段代码在单线程中执行的结果是有序的。注意是执行结果,因为虚拟机、处理器会对指令进行重排序。虽然重排序了,但是并不会影响程序的执行结果,所以程序最终执行的结果与顺序执行的结果是一致的。故而这个规则只对单线程有效,在多线程环境下无法保证正确性,可以把程序顺序规则看成as-if-serial语义的封装(所以说单线程执行保证也在hb中)。

锁定规则:这个规则比较好理解,无论是在单线程环境还是多线程环境,一个锁处于被锁定状态,那么必须先执行unlock操作后面才能进行lock操作。

volatile变量规则:这是一条比较重要的规则,它标志着volatile保证了线程可见性。通俗点讲就是如果一个线程先去写一个volatile变量,然后一个线程去读这个变量,那么这个写操作一定是happens-before读操作的。

传递规则:提现了happens-before原则具有传递性,即A happens-before B , B happens-before C,那么A happens-before C

线程启动规则:假定线程A在执行过程中,通过执行ThreadB.start()来启动线程B,那么线程A对共享变量的修改在接下来线程B开始执行后确保对线程B可见。

线程终结规则:假定线程A在执行的过程中,通过制定ThreadB.join()等待线程B终止,那么线程B在终止之前对共享变量的修改在线程A等待返回后可见。

happens-before规定的是不同线程之间的关系。

happen-before原则是JMM中非常重要的原则,它是判断数据是否存在竞争、线程是否安全的主要依据,保证了多线程环境下的可见性。

as-if-serial保证的是单线程内程序执行结果不会被指令重排序改变。幻境:单线程是按照程序顺序执行的。

happens-before保证的是正确同步的多线程程序执行结果不会被指令重排序改变。幻境:正确同步的多线程程序也是按照hb指定顺序执行的。

猜你喜欢

转载自blog.csdn.net/HNUST_LIZEMING/article/details/88370457