-
happens-before 规则含义:
happens-before原则是JMM最核心的概念,理解happens-before是理解JMM的关键。
JMM为了使编译器和处理器的约束尽可能少,它遵循的原则是:只要不改变程序的执行结果,编译器和处理器想怎么优化就怎么优化。happens-before原则简单理解:前一个操作的结果对后续操作可见。
JMM向程序员保证:一个操作happens-before于另一个操作,那么第一个操作的执行结果将对第二个执行结果可见,而且第一个操作的执行顺序排在第二个顺序之前。
happens-before原则的目的:为了在不改变程序执行结果的前提下,尽可能提高程序执行的并行度。
-
happens-before 规则定义
2.1 程序顺序规则
一个线程中,按程序顺序,前面的操作happens-before于后续任何操作。
例如int i = 1;// A int j = 2;// B int x = i*j;// C
A操作happens-before与B、C操作。
2.2 监控器锁规则
对一个锁的解锁,happens-before与随后对这个锁的加锁。
这个规则说的锁指的是java里的synchronized,例如下面代码,在正式进入同步代码块之前,会自动加锁,而在代码块执行结束后会自动释放锁,加锁和释放锁是编译器帮助我么实现的。synchronized(this){ // 自动加锁 if(this.name.equals("a")){ this.name = "b"; } }// 自动解锁
假设name的初始值是a,线程A执行完代码块后,name的值变成了b(执行完自动释放锁),线程B进入代码块可以看见线程A对name的操作,也就是线程B能看见name==“b”。
-
volatile变量规则
对一个volatile域的写,happens-before与任意后续对这个volatile域的读 -
传递性
如果A happens-before B, 且B happens-before C 那么A happens-before Cclass Demo { int x = 0; volatile boolean f = false; public void writer(){ x = 10; f = true; } public void reader(){ if( f == true ){ System.out.println(x); } } }
根据规则1:x = 10 happens-before 写变量 f = true ,
根据规则3:写变量 f = true happens-before 读变量 f = true
根据规则4 传递性:x = 10 happens 读变量 f = true 因此会输出 10。
-
start()规则
主线程A启动子线程B后,子线程B能看见主线程在启动子线程B的操作。 -
join()规则
如果线程A执行ThreadB.join()并成功返回,那么线程B的任意操作happens-before 于 线程A从ThreadB.join()操作成功返回。
总结:Happens-before的语义本质上是一种可见性,A happens-before B 意味着A事件对B事件来说是可见的,无论A事件和B事件是否发生在同一线程中。
JMM的设计分为两部分,一部分是happens-before原则,他是面向程序员提供的,阐述了一个强内存模型,我们只需要理解happens-before原则,就可以编写并发安全的程序了。 另一部分是针对JVM实现的,为了尽可能少的对编译器和处理器做约束,从而提高性能。JMM在不影响程序执行结果的前提下对其不做要求,即允许优化重排序。