Java内存模型,即 JMM (Java Memory Model),JMM 是一种规范,它规范了 JVM 运行的行为,多线程操作对共享内存读取时,所能读取到的值应该遵守的规则。提供了一些解决可见性和有序性问题的方法例如 volatile、synchronized 和 final 三个关键字。
JMM为程序中的所有操作定义了一定的规则,叫做Happens-Before 规则
Happens-Before 规则 解决了有序性和可见性的问题,如果你想保证你代码执行顺序不变(即有序性),你就需要遵守 Happens-Before 规则。要想保证操作A能看到操作B的结果,那么A、B之间一定要满足Happens-Before关系。happens-before并不是指操作A先于操作B发生,而是指操作A的结果在什么情况下可以被后面操作B所获取。
程序性顺序规则
:一个线程中,如果程序中A操作在B操作之前,那么线程中A操作将在B操作前执行。上锁原则
:不同线程对同一个锁的lock操作一定在unclock前。(先释放锁,才可以加锁,感觉也是废话)volatile 变量原则
:volatile 修饰变量的写操作,在读操作之前,也就是先写后读(详解看:volatile 关键字详解)线程启动原则
:线程A中启动线程B,即线程A中调用了线程B的start() 方法,那么start 操作在线程B其它操作之前。(感觉好像就是废话)传递规则
:如果A早于B执行,B早于C执行,那么A一定早于C执行。(好像也是废话)线程中断规则
:线程interrupt()方法的一定早于检测到线程的中断信号。线程终结规则
:如果线程A终结了,并且导致另外一个线程B中的ThreadA.join()方法取得返回,那么线程A中所有的操作都早于线程B在ThreadA.join()之后的动作发生。(B 线程调用A线程,A线程操作都早于B线程的操作,好想也是废话)对象终结规则
:一个对象初始化操作肯定先于它的finalize()方法。也就是说一个变量一旦被final 关键字修饰,且赋了初值,这个变量生下来就是不变的,即使怎么优化,没有任何影响。
总结
Happens-Before 是不是有一种因果关系的感觉。在现实世界里,如果 A 事件是导致 B 事件的起因,那么 A 事件一定是先于(Happens-Before)B 事件发生的,这个就是 Happens-Before 语义的现实理解。
Java 语言中,Happens-Before 的语义本质上是一种可见性,A Happens-Before B 意味着 A 事件对 B 事件来说是可见的,无论 A 事件和 B 事件是否发生在同一个线程里。例如 A 操作发生在线程 1 上,B 操作发生在线程 2 上,Happens-Before 规则保证线程 2 上也能看到 A 事件的发生。happens-before并不是指操作A先于操作B发生,而是指操作A的结果在什么情况下可以被后面操作B所获取。