Java的内存模型

Java内存结构见java运行原理
不要把概念弄混淆了。
内存模型实际上是描述程序的可能行为。
从java代码到class编译的过程当中,编译器会进行优化,指令重排,编译器将不会对存在数据依赖性的程序指令进行重排,这里的依赖性仅仅指单线程情况下的数据依赖性;多线程并发情况下,此规则将失效。
Java的内存模型
Java编程语言内存模型是java 虚拟机的规范,至于具体怎么实现可以任意,包括操作的重新排序和删除不必要的同步。

具体详情见官方文档:https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.4

根据Java内存模型中的规定,可以总结出以下几条happens-before规则。Happens-before的前后两个操作不会被重排序且后者对前者的内存可见。

  • 程序次序法则:线程中的每个动作A都happens-before于该线程中的每一个动作B,其中,在程序中,所有的动作B都能出现在A之后。
  • 监视器锁法则:对一个管城的解锁 happens-before于每一个后续对同一监视器锁的加锁。
  • volatile变量法则:对volatile域的写入操作happens-before于每一个后续对同一个域的读写操作。
  • 线程启动法则:在一个线程里,对Thread.start的调用会happens-before于每个启动线程的动作。
  • 线程终结法则:线程中的任何动作都happens-before于其他线程检测到这个线程已经终结、或者从Thread.join调用中成功返回,或Thread.isAlive返回false。
  • 中断法则:一个线程调用另一个线程的interrupt happens-before于被中断的线程发现中断。
  • 终结法则:一个对象的构造函数的结束happens-before于这个对象finalizer的开始。
  • 传递性:如果A happens-before于B,且B happens-before于C,则A happens-before于C。

当程序包含两个没有被happens-before关系排序的冲突访问时,就存在数据争用。遵守了这个原则,也就意味着有些代码不能进行重排序,有些数据不能缓存!