深入理解 JMM-CPU 多核硬件架构剖析及 Java 内存模型
前言
上一节了解 synchronized 关键字的底层原理以及锁的升级过程,本节带着大家了解 CPU 多核硬件架构以及 Java 内存模型
CPU 多核硬件架构剖析
CPU 每次从主内存读取数据比较慢,CPU 通常涉及多级缓存。CPU 读主内存的数据,按照空间局部性原则加载局部快照到缓存中
L1 L2 属于每个 CPU 中都是独立的缓存,缓存主内存共享变量的数据作为副本,L3 属于多个 cpu 之间共享的缓存。每个 cpu 之间都有独立二级缓存主内存的数据作为副本,而副本与副本之间是完全不可见的
总线仲裁机制
每次处理器和内存之间的数据传递都是通过一系列步骤来完成的,这一系列步骤称之为总线事务(Bus Transaction)
总线会同步试图并发使用总线的事务。在一个处理器执行总线事务期间,总线会禁止其他的处理器和 I/O 设备执行内存的读/写
总线的这种工作机制可以把所有处理器对内存的访问以串行化的方式来执行
在任意时间点,最多只能有一个处理器可以访问内存。这个特性确保了单个总线事务之中的内存读/写操作具有原子性
处理器提供总线锁定和缓存锁定两个机制来保证复杂内存操作的原子性
总线锁定
总线锁定就是使用处理器提供的一个 LOCK#信号,当其中一个处理器在总线上输出此信号时,其它处理器的请求将被阻塞住,那么该处理器可以独占共享内存
总线锁定会将并行的程序,变为串行
缓存锁定
缓存锁定是某个 CPU 对缓存数据进行更改时,会通知缓存了该数据的该数据的 CPU 抛弃缓存的数据或者从内存重新读取
在读写时要根据协议来进行操作,这类协议有 MSI、MESI、MOSI、Synapse、Firefly 及 DragonProtocol 等等,但是用的最多的就是 MESI。缓存一致性协议会锁缓存行,其性能要比锁总线要高得多
MESI 协议
M 修改 (Modified) 这行数据有效,数据被修改了,和主内存中的数据不一致,数据只存在于本 Cache 中。
E 独享、互斥 (Exclusive) 这行数据有效,数据和主内存中的数据一致,数据只存在于本 Cache 中。
S 共享 (Shared) 这行数据有效,数据和主内存中的数据一致,数据存在于很多 Cache 中。
I 无效 (Invalid) 这行数据无效。
JMM 内存模型
主内存
存放我们共享变量的数据
工作内存
每个 CPU 对共享变量(主内存)的副本
JMM 八大同步规范
read(读取):从主内存读取数据
load(载入):将主内存读取到的数据写入工作内存中
use(使用):从工作内存读取数据来计算
assign(赋值):将计算好的值重新赋值到工作内存中
store(存储):将工作内存数据写入主内存
write(写入):将 store 过去的变量值赋值给主内存中的变量
lock(锁定):将主内存变量加锁,标识位线程独占状态
unlock(解锁):将主内存变量解锁,解锁后其他线程可以锁定该变量
并发三大特性
可见性、原子性、有序性
可见性
可见性指的是当一个线程修改了某个共享变量的值,其他线程是否能够马上得知这个修改的值
如何保证可见性
通过 volatile 关键字保证可见性
通过 内存屏障保证可见性
通过 synchronized 关键字保证可见性。
通过 Lock 保证可见性
通过 final 关键字保证可见性
有序性
即程序执行的顺序按照代码的先后顺序执行。JVM 存在指令重排,所以存在有序性问题。多线程环境下,操作都是无序的,存在指令重排现象和工作内存与主内存同步延迟现象
如何保证有序性
通过 volatile 关键字保证可见性
通过 内存屏障保证可见性
通过 synchronized 关键字保证有序性
通过 Lock 保证有序性
原子性
原子性指的是一个操作是不可中断的,即使是在多线程环境下,一个操作一旦开始就不会被其他线程影响
如何保证原子性
通过 synchronized 关键字保证原子性
通过 Lock 保证原子性
通过 CAS 保证原子性
总结
本文主要介绍了 CPU 多核硬件架构剖析及 Java 内存模型
版权声明: 本文为 InfoQ 作者【janyxe】的原创文章。
原文链接:【http://xie.infoq.cn/article/b1cd04ed8e56cb9560f448d8c】。未经作者许可,禁止转载。
评论