在上一篇聊聊高并发(三十三)从一致性(Consistency)的角度理解Java内存模型 我们说了Java内存模型是一个语言级别的内存模型抽象。它屏蔽了底层硬件实现内存一致性需求的差异,提供了对上层的统一的接口来提供保证内存一致性的编程能力。
在一致性这个问题域中,各个层面扮演的角色大致例如以下:
1. 一致性模型,定义了各种一致性模型的理论基础
2. 硬件层,提供了实现某些一致性模型的硬件能力。硬件在默认情况下依照最主要的方式执行,比方
对同一个线程没有数据依赖的指令能够重排序优化运行,有数据依赖的指令依照程序顺序运行,从而保证单线程程序运行的正确性
保证读操作读到的数据肯定是之前在同一位置写入的数据
3. 语言层,少数语言提供了语言层面的满足一致性模型的编程能力,另外一些语言则直接使用硬件层提供了一致性编程的能力。提供一致性能力语言的工作方式例如以下:
把满足一致性需求的编程能力作为一种资源,指定一些规则,比方volitile, synchronized,Happens-before规则等
当应用层须要使用这样的编程能力的时候,须要显式地提出申请,比方显式地使用volatile来标识变量
通过编译器适配底层各种硬件平台提供了一致性编程的能力,比方有些平台使用内存屏障,有些平台使用read-modified-write。须要语言层来屏蔽这样的差异性
4. 应用层,比方分布式系统,比方并发的server程序。它们在一致性问题中的工作有
依据实际需求来定义应用所须要满足的一致性需求
定义和选择对应的实现一致性需求的算法。比方分布式存储中通过消息协议实现的Paxos,Zab。多阶段提交等
利用编程语言提供了主要的一致性编程的能力作为实现一致性需求算法的基础
说了一堆一致性需求相关的。那么问题来了。为什么有内存一致性的这个需求呢?
内存一致性需求的出现主要是由于多核CPU的出现,而且存在多级的快速缓存,这样就出现了对内存读写的并发问题,从而出现了内存的一致性问题。
所以快速缓存是造成内存一致性问题的一个重要原因。非常多写Java内存模型的文章笼统的说CPU写操作的时候存在一个写缓冲区write buffer。导致写操作不能及时写回到主存,造成了其它线程不能看到新写入的值,也就是所谓的可见性问题; 而且因为写缓存区是一种lazy write,导致了CPU能够在写没有刷新到内存的时候就開始兴许的读,也形成了重排序的场景。所谓的有序性的问题。
这篇文章写写CPU快速缓存相关的工作原理,来看看写缓存区究竟是个什么东西。本人不是研究硬件的,一些观点也是基于自己的理解。假设说的不正确请进一步查阅资料。
先来看一张图,这张就是Java内存模型的概念模型图。工作内存 work memory是对CPU寄存器和快速缓存的抽象。
再来看一张图,摘自《深入理解计算机系统》中描写叙述Intel Core i7