内存模型
内存模型
volatile
保证所有线程看到值一致,对单个volatile变量读写具有原子性 volatile++不具备
- lock前缀
- 当前处理器缓存行数据写会系统内存
- 写回内存的操作会使其它CPU里缓存了该内存地址的数据无效
- 多处理器的情况下,每个处理器通过嗅探在总线上传播的数据,检查自己的缓存是否过期
- 总线(Bus)是计算机各种功能部件之间传送信息的公共通信干线,它是由导线组成的传输线束, 按照计算机所传输的信息种类,计算机的总线可以划分为数据总线、地址总线和控制总线,分别用来传输数据、数据地址和控制信号。
- lock指令执行期间会锁住总线,使得其它处理器无法通过总线访问内存
锁的内存语义
线程获得锁时,JMM会使该线程对应的本地内存置为无效,临界区代码必须从主内存读取共享变量
基础
并发编程两个关键问题
- 如何通信、
- 共享内存
- java并发采用模型
- 消息传递
- 共享内存
- 如何同步
- 控制不同线程间操作的相对顺序
内存模型抽象
- jmm通过控制主内存与每个线程的本地内存之间的交互,来提供内存可见性的保证
- 主内存(共享变量)
- 本地内存A 共享变量的副本
- 线程A
- 本地内存B 共享变量的副本
- 线程B
- 本地内存A 共享变量的副本
指令执行
- 指令流水线有取指(IF)、译码(ID)、执行(EX)、访存(MEM)、写回寄存器堆(WB)5个阶段 每个阶段都要花费一个机器周期
重排序
- 过程
- 处理器重排序,可以插入内存屏障禁止特定类型的重排序
- 源代码
- 编译器优化
- 指令并行 指令并行技术 ILP
- 内存系统 读/写缓冲区
- 最终执行序列
- 概要: 处理器重排序,可以插入内存屏障禁止特定类型的重排序
- 数据依赖性
- as-is-serial
- 不管怎么排,结果不能变
- 多线程中,对存在控制依赖的重排序,可能会改变程序的执行结果
- 顺序一致性
内存屏障
- loadload
- loadstore
- storesore
- storeload
- 全能型
- 具备其它三个屏障的效果,开销很昂贵,会把缓冲区中所有数据刷入内存
- 全能型
Happen-Before
- 一个操作的结果要对另外一个操作可以见,那么这两个操作之间就存在happen before关系,使用于同一线程或者不同线程
final域内存语义
构造函数内对一个final域的写入,与随后将这个被构造对象的引用赋值给一个引用变量,不能重排序
- jmm禁止编译器把final域的写重排序到构造函数之外
- final域写之后,构造函数return之前,掺入storestore屏障
初次读一个包含final域的对象的引用与随后读,操作不能重排序
final引用不能从构造函数内溢出
双重检查锁定和延迟初始化
开销大的操作延迟加载
- 重排序解决方案
- volatile
- 类初始化解决方案
- 类初始化期间,jvm会去获得一个锁,可以同步多个线程对同一个类的初始化
- 初始化步骤
- 获取初始化锁
- 取得锁的线程A执行类初始化,读取到state=uninitialized,未取得锁的线程BCD…在condition中等待
- 线程A设置类已初始化state=initialized唤醒在condition中等待的所有县城
- B获取初始化锁,读取到state,已初始化,释放锁
- CD…执行
- 初始化步骤
- 类初始化期间,jvm会去获得一个锁,可以同步多个线程对同一个类的初始化
XMind: ZEN - Trial Version