Java作為一個跨平台的語言。它的實現要面對不同的底層硬件系統,設計一個中間層模型來屏蔽底層的硬件差異,給上層的開發人員一個一致的使用接口。Java內存模型就是這樣一個中間層的模型,它為程序猿屏蔽了底層的硬件實現細節,支持大部分的主流硬件平台。
要理解Java內存模型以及一些處理高並發的技術手段,理解一些主要的硬件知識是必須的。
這篇會說一下跟並發編程相關的一些硬件知識。
一個主要的CPU運行計算的步驟例如以下:
1. 程序以及數據被載入到主內存
2. 指令和數據被載入到CPU的快速緩存
3. CPU運行指令,把結果寫到快速緩存
4. 快速緩存中的數據寫回主內存
這個過程中,我們能夠看到有兩個問題
1. 現代的計算芯片都會集成一個L1快速緩存,我們能夠理解為每一個芯片都有一個私有的存儲空間。
那么當CPU的不同計算芯片要訪問同一個內存地址時,該內存地址的值會在CPU的不同計算芯片之間有多個拷貝,怎樣同步這些拷貝?
2. CPU讀寫是直接和快速緩存打交道。而不是和主內存直接打交道。由於通常一次主存訪問在幾十到幾百個時鍾周期。而一次L1快速緩存的讀寫僅僅須要1-2個時鍾周期,而一次L2快速緩存的讀寫僅僅須要數十個時鍾周期。
那么CPU寫到快速緩存的值何時寫回到主內?假設是多個計算芯片在處理同一個內存地址。那么怎樣處理這個時間差是個問題。
對於第一個問題。不同的硬件結構處理的方式不一樣。我們來理解一下互連線的概念。
互連線是處理器於主存以及處理器與處理器之間進行通信的媒介,有兩種主要的互聯結構:SMP(symmetric multiprocessing 對稱多處理)和NUMA(nonuniform memory access 非一致內存訪問)
SMP系統結構非常普通。由於它們最easy構建。非常多小型server採用這樣的結構。處理器和存儲器之間採用總線互聯。處理器和存儲器都有負責發送和監聽總線廣播的信息的總線控制單元。可是同一時刻僅僅能有一個處理器(或存儲控制器)在總線上廣播,全部的處理器都能夠監聽。
非常easy看出,對總線的使用是SMP結構的瓶頸。
NUMP系統結構中,一系列節點通過點對點網絡互聯,像一個小型互聯網,每一個節點包括一個或多個處理器和一個本地存儲器。一個節點的本地存儲對於其它節點是可見的,全部節點的本地存儲一起形成了一個能夠被全部處理器共享的全局存儲器。能夠看出,NUMP的本地存儲是共享的,而不是私有的,這點和SMP是不同的。NUMP的問題是網絡比總線復制。須要更加復雜的協議。處理器訪問自己節點的存儲器速度快於訪問其它節點的存儲器。NUMP的擴展性非常好,所以眼下非常多大中型的server在採用NUMP結構。
對於上層程序猿來說。最須要理解的是互連線是一種重要的資源。使用的好壞會直接影響程序的運行性能。
大概理解了不同的互連結構之后,我們來看看緩存一致性協議。它主要就是處理多個處理器處理同一個主存地址的問題。
MESI是一種主流的緩存一致性協議,已經用在Pentium和PowerPC處理器中。它定義了緩存塊的幾種狀態
- modified(改動):緩存塊已經被改動,必須被寫回主存。其它處理器不能再緩存這個塊
- exclusive(相互排斥):緩存塊還沒有被改動。且其它處理器不能裝入這個緩存塊
- share(共享):緩存塊未被改動。且其它處理器能夠裝入這個緩存塊
- invalid(無效):緩存塊中的數據無效
上圖展示了MESI快速緩存一致性協議的狀態轉換實例。
1. 在a中,處理器A從地址a讀取數據,將數據存入它的緩存並置為exclusive
2. 在b中。當處理器B試圖從同樣地址a讀取數據時。A檢測到地址沖突,以相關數據做出響應。此時a同一時候被A和B以shared狀態裝入緩存
3. 在c中,當B要對共享地址a進行寫操作。則將狀態改為modified,並廣播提醒A,讓它將它的緩存塊狀態設置為Invalid
4. 在d中。當A試圖從a讀取數據,會廣播它的請求。B則把它改動的數據發送到A和主存,並設置兩個副本的狀態為shared來做出響應
很多其它緩存一致性協議的細節參考這篇 http://blog.csdn.net/realxie/article/details/7317630
緩存一致性協議存在的一個最大的問題是可能引起緩存一致性流量風暴。之前我們看到總線在同一時刻僅僅能被一個處理器使用。當有大量緩存被改動,或者同一個緩存塊一直被改動時,會產生大量的緩存一致性流量。從而占用總線。影響了其它正常的讀寫請求。
一個最常見的樣例就是假設多個線程對同一個變量一直使用CAS操作。那么會有大量改動操作。從而產生大量的緩存一致性流量,由於每一次CAS操作都會發出廣播通知其它處理器,從而影響程序的性能。
后面我們會講怎樣優化這樣的使用方式。
對於第二個問題,怎樣處理改動數據從快速緩存到主內存的時間差。通常使用內存屏障來處理,后面會有專門的主題。
轉載請注明來源:http://blog.csdn.net/iter_zc