java内存模型和多线程环境

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

猜你喜欢

转载自blog.csdn.net/weixin_33742618/article/details/91070084