## 引言
由于CPU和主存的處理速度上存在一定差別,為了匹配這種差距,提升計算機能力,人們在CPU和主存之間增加了多層高速緩存。每個CPU會有L1、L2甚至L3緩存,在多核計算機中會有多個CPU,那么就會存在多套緩存,那么這多套緩存之間的數據就可能出現不一致的現象。為了解決這個問題,有了內存模型。內存模型定義了共享內存系統中多線程程序讀寫操作行為的規范。通過這些規則來規范對內存的讀寫操作,從而保證指令執行的正確性。
那么,內存模型到底是怎么保證緩存一致性的呢?
接下來我們試著回答這個問題。首先,緩存一致性是由于引入緩存而導致的問題,所以,這是很多CPU廠商必須解決的問題。為了解決前面提到的緩存數據不一致的問題,人們提出過很多方案,通常來說有以下2種方案:
* 1、通過在總線加LOCK#鎖的方式。
* 2、通過緩存一致性協議(Cache Coherence Protocol)。
在早期的CPU當中,是通過在總線上加LOCK#鎖的形式來解決緩存不一致的問題。因為CPU和其他部件進行通信都是通過總線來進行的,如果對總線加LOCK#鎖的話,也就是說阻塞了其他CPU對其他部件訪問(如內存),從而使得只能有一個CPU能使用這個變量的內存。在總線上發出了LCOK#鎖的信號,那么只有等待這段代碼完全執行完畢之后,其他CPU才能從其內存讀取變量,然后進行相應的操作。這樣就解決了緩存不一致的問題。
但是由于在鎖住總線期間,其他CPU無法訪問內存,會導致效率低下。因此出現了第二種解決方案,通過緩存一致性協議來解決緩存一致性問題。
## 緩存一致性協議
緩存一致性協議(Cache Coherence Protocol),最出名的就是Intel 的MESI協議,MESI協議保證了每個緩存中使用的共享變量的副本是一致的。
MESI的核心的思想是:當CPU寫數據時,如果發現操作的變量是共享變量,即在其他CPU中也存在該變量的副本,會發出信號通知其他CPU將該變量的緩存行置為無效狀態,因此當其他CPU需要讀取這個變量時,發現自己緩存中緩存該變量的緩存行是無效的,那么它就會從內存重新讀取。
> 在MESI協議中,每個緩存可能有有4個狀態,它們分別是:
> M(Modified):這行數據有效,數據被修改了,和內存中的數據不一致,數據只存在于本Cache中。
> E(Exclusive):這行數據有效,數據和內存中的數據一致,數據只存在于本Cache中。
> S(Shared):這行數據有效,數據和內存中的數據一致,數據存在于很多Cache中。
> I(Invalid):這行數據無效。
關于MESI的更多細節這里就不詳細介紹了,讀者只要知道,MESI是一種比較常用的緩存一致性協議,他可以用來解決緩存之間的數據一致性問題就可以了。
但是,值得注意的是,傳統的MESI協議中有兩個行為的執行成本比較大。
一個是將某個Cache Line標記為Invalid狀態,另一個是當某Cache Line當前狀態為Invalid時寫入新的數據。所以CPU通過Store Buffer和Invalidate Queue組件來降低這類操作的延時。
如圖:

當一個CPU進行寫入時,首先會給其它CPU發送Invalid消息,然后把當前寫入的數據寫入到Store Buffer中。然后異步在某個時刻真正的寫入到Cache中。
當前CPU核如果要讀Cache中的數據,需要先掃描Store Buffer之后再讀取Cache。
但是此時其它CPU核是看不到當前核的Store Buffer中的數據的,要等到Store Buffer中的數據被刷到了Cache之后才會觸發失效操作。
而當一個CPU核收到Invalid消息時,會把消息寫入自身的Invalidate Queue中,隨后異步將其設為Invalid狀態。
和Store Buffer不同的是,當前CPU核心使用Cache時并不掃描Invalidate Queue部分,所以可能會有極短時間的臟讀問題。
所以,為了解決緩存的一致性問題,比較典型的方案是MESI緩存一致性協議。
MESI協議,可以保證緩存的一致性,但是無法保證實時性。
## 內存模型
內存模型(Memory Model)如果擴展開來說的話,通常指的是內存一致性模型(Memory Sequential Consistency Model)
前面我們提到過緩存一致性,這里又要說內存一致性,不是故意要把讀者搞蒙,而是希望通過對比讓讀者更加清楚。
* 緩存一致性(Cache Coherence),解決是多個緩存副本之間的數據的一致性問題。
* 內存一致性(Memory Consistency),保證的是多線程程序訪問內存時可以讀到什么值。
我們首先看以下程序:
```
初始:x=0 y=0
Thread1:
S1:x=1
L1:r1=y
Thread2:
S2:y=2
L2:r2=x
```
其中,S1、S2、L1、L2是語句代號(S表示Store,L表示Load);r1和r2是兩個寄存器。x和y是兩個不同的內存變量。兩個線程執行完之后,r1和r2可能是什么值?
注意到線程是并發、交替執行的,下面是可能的執行順序和相應結果:
```
S1 L1 S2 L2 那么r1=0 r2=2
S1 S2 L1 L2 那么r1=2 r2=1
S2 L2 S1 L1 那么r1=2 r2=0
```
這些都是意料之內、情理之中的。但是在x86體系結構下,很可能得到r1=0 r2=0這樣的結果。
如果沒有Memory Consistency,程序員寫的程序代碼的輸出結果是不確定的。
因此,Memory Consistency就是程序員(編程語言)、編譯器、CPU間的一種協議。這個協議保證了程序訪問內存時會得到什么值。
簡單點說,內存一致性,就是保證并發場景下的程序運行結果和程序員預期是一樣的(當然,要通過加鎖等方式),包括的就是并發編程中的原子性、有序性和可見性。而緩存一致性說的就是并發編程中的可見性。
在很多內存模型的實現中,關于緩存一致性的保證都是通過硬件層面緩存一致性協議來保證的。需要注意的是,這里提到的內存模型,是計算機內存模型,而非Java內存模型。
## 總結
緩存一致性問題。硬件層面的問題,指的是由于多核計算機中有多套緩存,各個緩存之間的數據不一致性問題。
PS:這里還需要再重復一遍,Java多線程中,每個線程都有自己的工作內存,需要和主存進行交互。這里的工作內存和計算機硬件的緩存并不是一回事兒,只是可以相互類比。所以,并發編程的可見性問題,是因為各個線程之間的本地內存數據不一致導致的,和計算機緩存并無關系。
緩存一致性協議。用來解決緩存一致性問題的,常用的是MESI協議。
內存一致性模型。屏蔽計算機硬件問題,主要來解決并發編程中的原子性、有序性和一致性問題。
實現內存一致性模型的時候可能會用到緩存一致性模型。
- java
- 設計模式
- 設計模式總覽
- 設計原則
- 工廠方法模式
- 抽象工廠模式
- 單例模式
- 建造者模式
- 原型模式
- 適配器模式
- 裝飾者模式
- 代理模式
- 外觀模式
- 橋接模式
- 組合模式
- 享元模式
- 策略模式
- 模板方法模式
- 觀察者模式
- 迭代子模式
- 責任鏈模式
- 命令模式
- 備忘錄模式
- 狀態模式
- 訪問者模式
- 中介者模式
- 解釋器模式
- 附錄
- JVM相關
- JVM內存結構
- Java虛擬機的內存組成以及堆內存介紹
- Java堆和棧
- 附錄-數據結構的堆棧和內存分配的堆區棧區的區別
- Java內存之Java 堆
- Java內存之虛擬機和內存區域概述
- Java 內存之方法區和運行時常量池
- Java 內存之直接內存(堆外內存)
- JAVA內存模型
- Java內存模型介紹
- 內存模型如何解決緩存一致性問題
- 深入理解Java內存模型——基礎
- 深入理解Java內存模型——重排序
- 深入理解Java內存模型——順序一致性
- 深入理解Java內存模型——volatile
- 深入理解Java內存模型——鎖
- 深入理解Java內存模型——final
- 深入理解Java內存模型——總結
- 內存可見性
- JAVA對象模型
- JVM內存結構 VS Java內存模型 VS Java對象模型
- Java的對象模型
- Java的對象頭
- HotSpot虛擬機
- HotSpot虛擬機對象探秘
- 深入分析Java的編譯原理
- Java虛擬機的鎖優化技術
- 對象和數組并不是都在堆上分配內存的
- 垃圾回收
- JVM內存管理及垃圾回收
- JVM 垃圾回收器工作原理及使用實例介紹
- JVM內存回收理論與實現(對象存活的判定)
- JVM參數及調優
- CMS GC日志分析
- JVM實用參數(一)JVM類型以及編譯器模式
- JVM實用參數(二)參數分類和即時(JIT)編譯器診斷
- JVM實用參數(三)打印所有XX參數及值
- JVM實用參數(四)內存調優
- JVM實用參數(五)新生代垃圾回收
- JVM實用參數(六) 吞吐量收集器
- JVM實用參數(七)CMS收集器
- JVM實用參數(八)GC日志
- Java性能調優原則
- JVM 優化經驗總結
- 面試題整理
- 面試題1
- java日志規約
- Spring安全
- OAtuth2.0簡介
- Spring Session 簡介(一)
- Spring Session 簡介(二)
- Spring Session 簡介(三)
- Spring Security 簡介(一)
- Spring Security 簡介(二)
- Spring Security 簡介(三)
- Spring Security 簡介(四)
- Spring Security 簡介(五)
- Spring Security Oauth2 (一)
- Spring Security Oauth2 (二)
- Spring Security Oauth2 (三)
- SpringBoot
- Shiro
- Shiro和Spring Security對比
- Shiro簡介
- Session、Cookie和Cache
- Web Socket
- Spring WebFlux