JSR-133使用happens-before的概念来阐述操作之间内存的可见性,在JMM中如果一个操作的结果需要对另一个可见,那么这两个操作之间必须要存在happens-before规则
注意:两个操作之间有happens-before关系,并不意味着前一个操作必须要在后一个操作之前执行。happens-before仅仅要求前一个操作的(执行的结果)对后一个操作可见。
JMM的设计思想:程序员希望基于一个强内存模型来编写代码,编译器和处理器希望实现一个弱内存模型利于优化。设计JMM的核心目标就是找到一个平衡点:一方面要为程序员提供足够强的内存可见性的保证,另一方面,对编译器和处理器的限制要尽可能的放松。如此happens-before应运而生。
JMM把happens-before禁止到重排序分为了两类:会改变程序执行结果的重排序,以及不会改变程序执结果的重排序。
JMM对于这两种不同性质的重排序采用了不同的策略:对于会改变程序执行结果的重排序,JMM要求编译器和处理器必须禁止这种重排序,对于不改变程序结果的重排序,JMM对编译器和处理器不做要求(JMM允许这种重排序)。
JMM其实在遵循一个基本原则:只要不改变程序的执行结果,编译器和处理器想怎么优化都可以。
happens-before规则内容
1、程序次序原则:一个线程内,按照程序代码顺序,书写在前面的操作先行发生与书写在后面的操作。
2、监视器锁规则:一个unlock操作先行发生与后面对同一个锁的lock操作者,这里必须指同一个锁,后面指的是时间上的先后顺序。
3、volatile变量规则:对一个volatile变量的写操作先行发生于后面对这个变量的读操作,这里的后面同样指时间上的先后顺序。
4、线程启动规则:Thread对象的start方法先行发生于此线程的每一个动作
5、线程终止规则:线程中的所有操作都先行发生于对此线程的终止检测,我们可以通过thread.join方法结束,thread.isAlive的返回值等手段检测到线程已经终止执行
6、线程中断原则:对线程interrupt方法的调用先行发生于被中断线程的代码监测到中断时间的发生,可以通过interrupt方法检测到是否又中断发生
7、对象终结规则:一个对象的初始化完成,先行发生于它的finalize方法的开始
8、传递性:如果A先行发生于B,B先行发生于C,则A先行发生于C
注意:时间先后顺序与先行发生原则之间没有太大的关系,所以我们衡量并发安全问题的时候不要受时间顺序的干扰,一切以“先行发生原则”为准。