https://www.infoq.cn/profile/1278512
runtime data area
http://coding-geek.com/jvm-memory-model/
一、 重排序与顺序一致性
二、 三个同步原语(lock,volatile,final)的内存语义
三、重排序规则及在处理器中的实现
四、java内存模型的设计,及其与处理器内存模型和顺序一致性内存模型的关系。
runtime data areas
http://coding-geek.com/jvm-memory-model/
多线程间的通信: 共享内存
同步: 控制不同线程之间操作发生相对顺序
内存可见性问题
JMM决定一个线程对共享变量的写入何时对另一个线程可见
线程私有local memory
线程间共享主内存 main memory
local memory 和 main memory 都是抽象概念。
local memory 拷贝 main memory 共享变量的副本。
分拆成 读、写 两部操作。
重排序
编译器重排序
指令重排序
内存重排序
其中指令重排序和内存重排序都是处理器重排序
处理器重排序属于操作系统和硬件的问题, 为了维护JMM的规范, 编译器重排序和内存屏障维护了JMM
内存屏障 可以解决 处理器重排序的问题, 是jvm内部实现
程序员关注到 编译器重排序和内存屏障就够了。无需继续深入到处理器重排序。
JMM规范抽象出的 happens-before原则
注意,两个操作之间具有 happens-before 关系,并不意味着前一个操作必须要在后一个操作之前执行!happens-before 仅仅要求前一个操作(执行的结果)对后一个操作可见,且前一个操作按顺序排在第二个操作之前(the first is visible to and ordered before the second)。happens- before 的定义很微妙,后文会具体说明 happens-before 为什么要这么定义。
仅仅要求 前一个操作对后一个操作可见。
顺序一致性内存模型(抽象概念)
JMM实现这个概念
先把顺序一致性这个概念单独拎出来:
JMM 不保证对 64 位的 long 型和 double 型变量的读 / 写操作具有原子性,而顺序一致性模型保证对所有的内存读 / 写操作都具有原子性。
volatile
被volatile修饰的域(变量),happens-before 对域(变量)的读
监视器锁的语义决定了临界区代码的执行具有原子性。这意味着即使是 64 位的 long 型和 double 型变量,只要它是 volatile 变量,对该变量的读写就将具有原子性。如果是多个 volatile 操作或类似于 volatile++ 这种复合操作,这些操作整体上不具有原子性。
构造函数, 单例模式(懒汉式), 多线程环境下
构造函数开始执行
写final域
构造函数执行结束
线程A
obj = new ObjectA()
只有当构造函数的 jvm stack -> frame(栈帧)弹出, obj才会被赋值,否则obj保持null不变
并且加锁了, 在锁释放前local memory 中的数据会被刷新到 main memory
线程B
obj.execMethod()
final和volatile对重排序的影响, 锁对内存可见性的影响(所谓的内存可见性就是 local memory 中的变量刷新到 main memory )
JMM遵守 happens-before原则
但是允许重排序
final和volatile对重排序的影响
锁对内存可见性的影响(所谓的内存可见性就是 local memory 中的变量刷新到 main memory )
单个线程local memory中的写变量对外部不可见
main memory中的变量对外部可见的
当线程释放锁时,JMM 会把该线程对应的本地内存中的共享变量刷新到主内存中。
转载于:https://www.jianshu.com/p/f3ff5e5c4442