前言
上一节理解 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 保障原子性