当代多核(core)CPU中,通常是每个核(core)都有一级或两级高速缓存(cache),高速缓存较好解决了CPU与内存(RAM)的速度矛盾,但引入了新的问题,即:缓存一致性(Cache Coherence)。
同一数据的多个副本可能同时存在于不同核(core)的高速缓存(cache)中。若允许CPU自由地修改它们自己的副本,就会导致不同核(core)的高速缓存(cache)对存储器中同一数据的反映不一致。
建议先阅读此篇:计算机组成原理_CPU缓存 ,了解CPU缓存、MESI的概念为后续内容理解提供支撑。
操作系统层面的解决方案:
- 总线加锁 或者 cache line加锁
- 缓存一致性协议
1. 术语约定
- 线程工作内存 = 线程本地内存
- 主存 = Main Memory = 多个DRAM内存模块组成 = 内存条
- core = CPU的一个核心
2. Java Memory Model
Java定义了一种Java内存模型(Java Memory Model)来屏蔽掉各种硬件和操作系统的内存访问差异,以实现让Java程序在各种平台下都能达到一致的内存访问效果。
The Java Memory Model describes what behaviors are legal in multithreaded code, and how threads may interact through memory. It describes the relationship between variables in a program and the low-level details of storing and retrieving them to and from memory or registers in a real computer system. It does this in a way that can be implemented correctly using a wide variety of hardware and a wide variety of compiler optimizations. ---- 详阅 JSR 133 (Java Memory Model) FAQ
Java内存模型(Java Memory Model)控制了Java线程之间的通信,其采用共享内存
通信机制,线程间的通信是隐式的,而同步是显示进行的,Java内存模型(Java Memory Model)决定了一个线程对共享变量的写入何时对另一个线程可见。
从抽象的角度看,Java内存模型(Java Memory Model)定义了线程和主内存之间的抽象关系:线程之间的共享变量存储在主内存(Main Memory)中,每个线程都有一个私有的本地内存(Local Memory),本地内存中存储了该线程读写共享变量的副本。
3. Java Memory Model 数据原子操作
线程如何从主内存中获取数据,写入线程工作内存中?
线程操作、更新完数据,又是如何将线程工作内存中的数据回写到主内存中的?
3.1. 八个原子操作
Java Memory Model
通过执行以下八个原子操作,确保数据在主内存与线程工作内存流转过程中的准确。
- use - 使用
从线程的工作内存读取数据用于计算。
A use action (by a thread) transfers the contents of the thread’s working copy of a variable to the thread’s execution engine. This action is performed whenever a thread executes a virtual machine instruction that uses the value of a variable.
- assign - 赋值
将线程计算好的值重新赋值到线程的工作内存中。
An assign action (by a thread) transfers a value from the thread’s execution engine into the thread’s working copy of a variable. This action is performed whenever a thread executes a virtual machine instruction that assigns to a variable.
- read - 读取
把从主内存读取的数据传输到线程的工作内存中,供后续load
操作使用。
A read action (by the main memory) transmits the contents of the master copy of a variable to a thread’s working memory for use by a later load operation.
- load - 载入
把read
操作从主内存中读取到的数据放入线程的工作内存。
A load action (by a thread) puts a value transmitted from main memory by a read action into the thread’s working copy of a variable.
- store - 存储
把线程工作内存中的变量值传送到主内存中,供后续write
操作使用。
A store action (by a thread) transmits the contents of the thread’s working copy of a variable to main memory for use by a later write operation.
- write - 写入
把store
操作从线程工作内存得到的变量值写入主内存中。
A write action (by the main memory) puts a value transmitted from the thread’s working memory by a store action into the master copy of a variable in main memory.
- lock - 锁定
由一个与主内存紧密同步的线程来完成(可以认为是由主内存执行),将主内存变量加锁,标识为线程独占状态。
A lock action (by a thread tightly synchronized with main memory) causes a thread to acquire one claim on a particular lock.
- unlock - 解锁
由一个与主内存紧密同步的线程来完成(可以认为是由主内存执行),将主内存变量解锁。
An unlock action (by a thread tightly synchronized with main memory) causes a thread to release one claim on a particular lock.
3.2. 操作流转示意图
结合下面的示例代码,理解原子操作。
主内存中 interruptFlag = false
程序启动,线程1开始运行,通过
read
操作从主内存中读取interruptFlag = false,保存到线程工作内存中。通过
load
操作,把false赋值给工作内存中的interruptFlag。线程1从工作内存读取数据,用于逻辑处理。
以上,线程1 和 线程2 都是一样的。
此时,线程1的逻辑在等待interruptFlag值做出改变,以中断程序;而线程2正准备更新interruptFlag值。
线程2将interruptFlag值改为true。
通过
assign
操作,将interruptFlag改变后的值传输到线程工作内存中。通过
store
操作,将线程工作内存中interruptFlag改变后的值,传送到主内存中。然后通过
write
操作,将 interruptFlag=true 写入主内存。
注意:此时线程2修改 interruptFlag = true,对于线程1还是不可见的,因为 interruptFlag 没有使用volatile
关键字修饰。
3.3. 示例代码
线程1将interruptFlag字段值更新,如果没有添加volatile
关键字的,线程2是无法感知到数据变更的。
直观的体现了Java内存模型中的可见性问题。
1 | public class TestApp { |
4. Reference
- 《深入理解计算机系统原理 第三版》
- 《JLS - The Java Language Specification Java SE 8 Edition》(Chapter 17. Threads and Locks)
- 《JSR-133 - Java Memory Model and Thread Specification》(JSR-133在JDK5中实现,是对JLS中的补充和完善)
- The Java Memory Model (umd.edu)
- JSR 133 (Java Memory Model) FAQ - Jeremy Manson and Brian Goetz, February 2004
- www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html
- VM Spec Threads and Locks (oracle.com)
- 深入理解Java内存模型
- 深入理解Java内存模型_Java_程晓明_InfoQ精选电子书
- RedSpider社区简介 · 深入浅出Java多线程
- Java JMM(Java Memory Model)