Java内存模型(JMM) happens-before原则详解

JMM(JAVA内存模型)中,如果一个操作执行的结果需要对另一个操作可见,那么这两个操作之间必须存在happens-before关系。

JMM可以通过happens-before关系向程序员提供跨线程的内存可见性保证(如果A线程的写操作a与B线程的读操作b之间存在happensbefore关系,尽管a操作和b操作在不同的线程中执行,但JMM向程序员保证a操作将对b操作可见)。

happens-before原则:

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

happens-before规则:

  • 程序次序规则:一个线程内,按照代码顺序,书写在前面的操作先行发生于书写在后面的操作;
  • 锁定规则:一个unLock操作先行发生于后面对同一个锁额lock操作;
  • volatile变量规则:对一个volatile域的写,happens-before于任意后续对这个volatile域的读
  • 传递规则:如果A happens-before B,且B happens-before C,那么A happens-before C
  • 线程启动规则:如果线程A执行操作ThreadB.start()(启动线程B),那么A线程的ThreadB.start()操作- happens-before于线程B中的任意操作
  • 线程中断规则:对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生;
  • 线程终结规则:线程中所有的操作都先行发生于线程的终止检测,我们可以通过Thread.join()方法结束、Thread.isAlive()的返回值手段检测到线程已经终止执行;
  • 对象终结规则:一个对象的初始化完成先行发生于他的finalize()方法的开始;

通俗解释:

第一次接触该概念是在 方腾飞写的<<JAVA并发编程的艺术>>这本书, 初次接触感觉整章概念比较多, 有些晦涩, 在反复阅读和求助大神后有了一些理解, 记录在这

这条happens-before规则让人费解的地方就是happens-before规则的描述到底和谁在前边谁先执行有什么区别

<<JAVA并发编程的艺术>>有一句注意: 两个操作之间具有happens-before关系,并不意味着前一个操作必须要在后一个操作之前执行!happens-before仅仅要求前一个操作(执行的结果)对后一个操作可见,且前一个操作按顺序排在第二个操作之前。

这句话就是对这个问题的解释, 但也是让我最费解的一句话, 我们拆开理解:

happens-before仅仅要求前一个操作(执行的结果)对后一个操作可见的意思是前一个操作的结果计算完成并刷新到主内存, 后一个操作的线程也就能看到前一个操作的执行结果, 也就是对后一个操作可见
不意味着前一个操作必须要在后一个操作之前执行, 这句话的意思就是我们刚才说的谁在前边谁执行, 关键在于,执行这句话包含的不是一个时间点, 执行一个操作在cpu中是一个过程, 一个时间段, 一个操作必须要在后一个操作之前执行说的操作的开始,也就是这个执行时间段的开始, 总结起来这半句话的翻译就是:

不意味着前一个操作要在后一个操作之前开始执行 且前一个操作按顺序排在第二个操作之前, 这个操作顺序指的是操作的结果发生的顺序, 前一个比后一个先执行结束

总结一下这句话: happens-before不要求前一个操作和后一个操作的发生顺序, 仅仅要求前一个操作的执行完成并刷新回内存发生在后一个操作结果之前

为啥要区别操作的开始和结束呢?

大家应该也能猜到, 先开始的操作不一定先结束,JMM可以通过重排序等手段让代码顺序里靠后的指令先执行, 至于为什么要这样要去理解重排序的意义: 为啥要指令重排序

为啥要强调完成并刷新回内存(对后操作可见)呢?

这个是因为JAVA内存模型有本地缓存的抽象概念, 指令执行完结果放在本地缓存其他线程是看不到的, 要刷新回主内存对其他线程才可见(大家看到内存的结果才知道这个指令执行完了) , 这要大家去看JAVA内存模型(JMM)

发布了241 篇原创文章 · 获赞 407 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/qq_33709508/article/details/105342342

相关文章