Java内存模型 下

最近看到一个专题讲解Java内存模型的,感觉干货满满,现记录如下:

深入理解Java内存模型(一)——顺序

深入理解Java内存模型(二)——重排序

深入理解Java内存模型(三)——顺序一致性

深入理解Java内存模型(四)——volatile

深入理解Java内存模型(五)——锁

深入理解Java内存模型(六)——final

深入理解Java内存模型(七)——总结

在我之前的一篇博客Java内存模型 上一文里,对Java的内存做了一番简单的梳理。通过上述专题的阅读和学习,又有了新的认识和思考。

关于Java的锁

当线程释放锁时,JMM会把该线程对应的本地内存中的共享变量刷新到主内存中。这一操作和volatile变量的写操作相同功效

当线程获取锁时,JMM会把该线程对应的本地内存置为无效,这一操作和volatile变量的读操作相同共享

也即是文中总结的:锁释放与volatile写有相同的内存语义;锁获取与volatile读有相同的内存语义。

由此也自然联想到,Java锁的内部实现,其实就是通过volatile来实现的。

这里还涉及到公平锁,和非公平锁,这两者的区别是:

公平的锁上,线程按照他们发出请求的顺序获取锁.当一个线程请求非公平锁时,如果在发出请求的同时该锁变成可用状态,那么这个线程会跳过队列中所有的等待线程而获得锁。

关于Java的final

对于final域,编译器和处理器要遵守两个重排序规则:

  1. 在构造函数内对一个final域的写入,与随后把这个被构造对象的引用赋值给一个引用变量,这两个操作之间不能重排序。
  2. 初次读一个包含final域的对象的引用,与随后初次读这个final域,这两个操作之间不能重排序。

在构造函数内部,不能让这个被构造对象的引用为其他线程可见,也就是对象引用不能在构造函数中“逸出”。

重排序

重排序分为两大类:

  1. 编译器重排序
  2. 处理器重排序,该排序可细化为指令级并行的重排序和内存系统的重排序

内存屏障:对于处理器重排序,JMM的处理器重排序规则会要求java编译器在生成指令序列时,插入特定类型的内存屏障(memory barriers,intel称之为memory fence)指令,通过内存屏障指令来禁止特定类型的处理器重排序(不是所有的处理器重排序都要禁止)

内存模型

越是追求性能的处理器,内存模型设计的会越弱,模型由强变弱依次为:

  1. 顺序一致性内存模型

  2. JMM

  3. 处理器内存模型

happens-before:如果一个操作执行的结果需要对另一个操作可见,那么这两个操作之间必须存在happens-before关系。这里提到的两个操作既可以是在一个线程之内,也可以是在不同线程之间.

参考资料

Java 理论与实践: JDK 5.0 中更灵活、更具可伸缩性的锁定机制