系列介紹
本系列主要重點介紹Java中的J.U.C并發(fā)編程煌张,從原理早歇,理論到實踐的過程焰檩,帶你一步步了解各種知識點憔涉,把所有技術點構成一個閉環(huán),形成一個知識體系析苫。
希望在J.U.C系列對你有新的了解和認知兜叨。
第一步,我想從計算機的底層模型來做為我這個系列的開頭衩侥,因為你只有理解了計算機的原理和結構浪腐,才能對于Java的一些設計(J.U.C,Sync顿乒,JMM)才有更加深刻的理解和使用。
本章節(jié)不涉及到Java相關的知識點泽谨。
現(xiàn)代計算機理論模型
現(xiàn)代計算機模型是基于-馮諾依曼計算機模型
也稱馮·諾伊曼模型(Von Neumann model)或普林斯頓結構(Princeton architecture)璧榄,是一種將程序指令存儲器和數(shù)據(jù)存儲器合并在一起的計算機設計概念結構特漩。依據(jù)馮·諾伊曼結構設計出的計算機稱做馮.諾依曼計算機,又稱存儲程序計算機骨杂。
計算機在運行指令時涂身,會從存儲器中一條條指令取出,通過譯碼(控制器)搓蚪,從存儲器中取出數(shù)據(jù)蛤售,然后進行指定的運算和邏輯等操作,然后再按地址把運算結果返回內(nèi)存中去妒潭。
接下來悴能,再取出下一條指令,在控制器模塊中按照規(guī)定操作雳灾。依此進行下去漠酿。直至遇到停止指令。
程序與數(shù)據(jù)一樣存貯谎亩,按程序編排的順序炒嘲,一步一步地取出指令,自動地完成指令規(guī)定的操作是計算機最基本的工作模型匈庭。這一原理最初是由美籍匈牙利數(shù)學家馮.諾依曼于1945年提出來的夫凸,故稱為馮.諾依曼計算機模型。
計算機五大核心組成部分
-
控制器(Control):
- 是整個計算機的中樞神經(jīng)阱持,其功能是對程序規(guī)定的控制信息進行解
釋夭拌,根據(jù)其要求進行控制,調(diào)度程序紊选、數(shù)據(jù)啼止、地址,協(xié)調(diào)計算機各部分工作及內(nèi)存與外設的訪問等兵罢。
- 是整個計算機的中樞神經(jīng)阱持,其功能是對程序規(guī)定的控制信息進行解
-
運算器(Datapath)
- 運算器的功能是對數(shù)據(jù)進行各種算術運算和邏輯運算献烦,即對數(shù)據(jù)進
行加工處理。
- 運算器的功能是對數(shù)據(jù)進行各種算術運算和邏輯運算献烦,即對數(shù)據(jù)進
-
存儲器(Memory)
- 存儲器的功能是存儲程序卖词、數(shù)據(jù)和各種信號巩那、命令等信息,并在需
要時提供這些信息此蜈。
- 存儲器的功能是存儲程序卖词、數(shù)據(jù)和各種信號巩那、命令等信息,并在需
-
輸入(Input system)
- 略即横,輸入設備有鍵盤、鼠標器等裆赵。
-
輸出(Output system)
- 略东囚。打印機等。
上圖為計算機模型流程圖
- 計算器
- 實際上就是CPU的工作
- 存儲器
- 計算器中的內(nèi)存(RAM)
上圖的重點只需要看中間的部分战授,本質的邏輯就是CPU页藻、存儲桨嫁。CPU是如何存儲數(shù)據(jù),計算份帐;CPU璃吧、存儲是如何交互通信的。
現(xiàn)代計算機硬件結構原理
下圖為計算器硬件的結構原理圖
拓展槽:指的內(nèi)存條废境。
我們可以把重點放到CPU,I/O總線畜挨,拓展槽上面,那為何結構是這樣設計的噩凹?
無論是CPU巴元、存儲器、或者我們的計算器中的顯示器栓始、鼠標务冕、鍵盤都是通過I/O總線來做交互通信。
I/O總線可以理解為一條高速通道幻赚,在這其中禀忆,CPU的頻率最高的達到GHz,而內(nèi)存條頻率遠遠無法和CPU相比擬落恼,而玩過游戲的小伙伴也知道箩退,對計算器的顯存也是會在I/O總線上面做通信,如此之多的模塊都在這上面佳谦,而CPU又是極高的頻率戴涝。
所以CPU的結構原理就會有一個CPU Cache
的設計,就是會把收到的指令復制一遍存到CPU Cache中钻蔑,進行計算啥刻。
運行速度來對比的:寄存器 > L1 > L2 > L3 > 內(nèi)存條
,而內(nèi)存條的讀寫速率遠遠小于CPU Cache咪笑,所以這個也是會有CPU Cache的設計產(chǎn)生的原因之一可帽。
因為內(nèi)存條的頻率遠遠小于CPU,所以才會有了CPU Cache
的出現(xiàn)窗怒,內(nèi)存條把編譯后的指令映跟,通過I/O總線放到CPU Cache
中,進行計算和存儲扬虚。
CPU
CPU內(nèi)部結構劃分努隙,主要有三種類型的單元
-
控制單元
- 控制單元是整個CPU的指揮控制中心,由指令寄存器IR(Instruction Register)辜昵、指令譯碼器ID(Instruction Decoder)和 操作控制器OC(Operation Controller) 等組成荸镊,對協(xié)調(diào)整個電腦有序工作極為重要。它根據(jù)用戶預先編好的程序,依次從存儲器中取出各條指
令贷洲,放在指令寄存器IR中收厨,通過指令譯碼(分析)確定應該進行什么操作,然后通過操作控制器OC优构,按確定的時序,向相應的部件發(fā)出微操作控制信號雁竞。操作控制器OC中主要包括:節(jié)拍脈沖發(fā)生器钦椭、控制矩陣、時鐘脈沖發(fā)生器碑诉、復位電路和啟停電路等控制邏輯彪腔。
- 控制單元是整個CPU的指揮控制中心,由指令寄存器IR(Instruction Register)辜昵、指令譯碼器ID(Instruction Decoder)和 操作控制器OC(Operation Controller) 等組成荸镊,對協(xié)調(diào)整個電腦有序工作極為重要。它根據(jù)用戶預先編好的程序,依次從存儲器中取出各條指
-
運算單元
- 運算單元是運算器的核心〗裕可以執(zhí)行算術運算(包括加減乘數(shù)等基本運算及其附加運算)和邏輯運算(包括移位德挣、邏輯測試或兩個值比較)。相對控制單元而言快毛,運算器接受控制單元的命令而進行動作格嗅,即運算單元所進行的全部操作都是由控制單元發(fā)出的控制信號來指揮的,所以它是執(zhí)行部件唠帝。
-
存儲單元
- 存儲單元包括 CPU 片內(nèi)緩存Cache和寄存器組屯掖,是 CPU 中暫時存放數(shù)據(jù)的地方,里面保存著那些等待處理的數(shù)據(jù)襟衰,或已經(jīng)處理過的數(shù)據(jù)贴铜,CPU 訪問寄存器所用的時間要比訪問內(nèi)存的時間短。 寄存器是CPU內(nèi)部的元件瀑晒,寄存器擁有非常高的讀寫速度绍坝,所以在寄存器之間的數(shù)據(jù)傳送非常快苔悦。采用寄存器轩褐,可以減少 CPU 訪問內(nèi)存的次數(shù),從而提高了 CPU 的工作速度间坐。寄存器組可分為專用寄存器和通用寄存器灾挨。專用寄存器的作用是固定的,分別寄存相應的數(shù)據(jù)竹宋;而通用寄存器用劳澄。
CPU寄存器
每個CPU都包含一系列的寄存器,它們是CPU內(nèi)內(nèi)存的基礎蜈七。CPU在寄存器上執(zhí)行操作的速度遠大于在主存上執(zhí)行的速度秒拔。這是因為CPU訪問寄存器的速度遠大于主存。
CPU緩存
即高速緩沖存儲器飒硅,是位于CPU與主內(nèi)存間的一種容量較小但速度很高的存儲器砂缩。由于CPU的速度遠高于主內(nèi)存作谚,CPU直接從內(nèi)存中存取數(shù)據(jù)要等待一定時間周期竖席,Cache中保存著CPU剛用過或循環(huán)使用的一部分數(shù)據(jù)属桦,當CPU再次使用該部分數(shù)據(jù)時可從Cache中直接調(diào)用,減少CPU的等待時間唁情,提高了系統(tǒng)的效率敢靡。
內(nèi)存
一個計算機還包含一個主存蝶锋。所有的CPU都可以訪問主存羞秤。主存通常比CPU中的緩存大得多绷落。拨黔、
上面的圖好乐,指的是內(nèi)存是如何和CPU進行交互工作的匾竿,我們大概知道這個內(nèi)存結構就可以了,希望幫助大家了解一下整體的結構蔚万,了解計算機是這樣的工作方式的岭妖,達成一個認知即可。
問題舉例1
public static void main(String[] args) {
int i = 0;
i = 1 + 1;
System.out.println(i);
}
假如執(zhí)行命令的main方法的時候反璃,CPU昵慌、內(nèi)存會按照如下的流程進行讀取存儲
1 . 初始化忽略,從 i = 1 + 1
,開始版扩,內(nèi)存會把這條指令發(fā)送到CPU中
- CPU寄存器會去讀确侠搿(load)i的內(nèi)存地址,然后交由
ALU
進行計算礁芦,計算結果(i=2)
會以此緩存到L1蜻韭,L2,L3; - CPU會在空閑的時候再把結果同步到內(nèi)存到柿扣,不會立馬同步到內(nèi)存中肖方,同步的條件,只有在自身的緩存內(nèi)存空間不足未状,才會進行寫入同步到內(nèi)存中俯画,那有沒有什么辦法可以把結果硬性的同步到內(nèi)存中?
這里先引申出一個概念 : MESI緩存一致性協(xié)議
CPU多核緩存架構
問題舉例2
有兩個線程T1,T2分別到CPU1,CPU2去執(zhí)行司草,執(zhí)行以下代碼方法
private static int i = 0;
public static void main(String[] args) {
i +=1;
System.out.println(i);
}
按照上面的結構艰垂,每個CPU都是獨立,并且每個線程都保持有自己的對于i的一個副本埋虹,也就是i + 1
猜憎,每個CPU在回寫同步數(shù)據(jù)結果的時候,并不知道其他的CPU也在針對i的內(nèi)存地址的結果進行計算回寫搔课,所以有可能有出現(xiàn)計算錯誤胰柑。
當各自的線程在CPU執(zhí)行完指令之后,實際的結果并非是 i + 1(T1) + 1(T2)
的結果,有可能是 i = 2
柬讨,這個就會出現(xiàn)我們的數(shù)據(jù)一致性問題崩瓤。
緩存一致性問題
在多處理器系統(tǒng)中,每個處理器都有自己的高速緩存踩官,而它們又共享同一主內(nèi)存(MainMemory)却桶。基于高速緩存的存儲交互很好地解決了處理器與內(nèi)存的速度矛盾蔗牡,但是也引入了新的問題:緩存一致性(CacheCoherence)肾扰。當多個處理器的運算任務都涉及同一塊主內(nèi)存區(qū)域時,將可能導致各自的緩存數(shù)據(jù)不一致的情況蛋逾,如果真的發(fā)生這種情況,那同步回到主內(nèi)存時以誰的緩存數(shù)據(jù)為準呢窗悯?為了解決一致性的問題区匣,需要各個處理器訪問緩存時都遵循一些協(xié)議,在讀寫時要根據(jù)協(xié)議來進行操作蒋院,這類協(xié)議有MSI亏钩、MESI(IllinoisProtocol)、MOSI欺旧、Synapse姑丑、Firefly及DragonProtocol,等等辞友。
總線加鎖(奔騰處理器)這個是很早之前的一個CPU的實現(xiàn)方法栅哀,這個的原理就是每次CPU要把數(shù)據(jù)回寫到內(nèi)存中的時候,都需要去總線中獲取一個鎖称龙,獲取鎖之后才可能把數(shù)據(jù)寫入到內(nèi)存中留拾。而沒有獲取到鎖的CPU就需要等待,直到獲取鎖為止鲫尊。
MESI協(xié)議
Cache line : Cache中最小緩存單位
-
M
- 狀態(tài):修改
- 描述 : 該Cache line有效痴柔,數(shù)據(jù)被修改了,和內(nèi)存中的數(shù)據(jù)不一致疫向,數(shù)據(jù)只存在于本Cache中咳蔚。
- 監(jiān)聽任務: Cache line 必須時刻監(jiān)聽所有試圖讀該Cache line 相對就內(nèi)存的操作,這種操作必須在緩存將Cache line寫回主內(nèi)存并將狀態(tài)變成S(共享)狀態(tài)之前被延遲執(zhí)行搔驼。
-
E
- 狀態(tài):共享(Shared)
- 描述 : 該Cache line有效谈火,數(shù)據(jù)和內(nèi)存中的數(shù)據(jù)一致,數(shù)據(jù)存在于很多的Cache中
- 監(jiān)聽任務: Cache line 必須監(jiān)聽其他緩存使該Cache line無效或者獨享該Cache line的請求匙奴,并將該Cache line更換狀態(tài)為無效(Invaild)堆巧。
-
I
- 狀態(tài):無效(Invaild)
- 描述 : 該Cache line無效,無法做任何操作,不能回寫數(shù)據(jù)到主內(nèi)存中谍肤。
- 監(jiān)聽任務: 無
CPU Cache line會時時刻刻的去嗅探 BUS(緩存一致性協(xié)議)啦租,監(jiān)聽是否有新的狀態(tài)改變,是否有新的指令(#LOCK等)荒揣,以此來改變自身的Cache Line的狀態(tài)篷角,以便后續(xù)可以做相應的操作。
問題舉例2-解決
- T1會從主內(nèi)存load到指令到CPU1中系任,然后會把對應的Cache line狀態(tài)變成
S(獨占)
狀態(tài)恳蹲; - T2也執(zhí)行同樣操作,因為有2個CPU獲取了同一個主內(nèi)存的數(shù)據(jù)俩滥,所以T2的Cache line 會變成一個
S(Shared)
狀態(tài)嘉蕾,T1中的Cache line會從S(獨占) --> E(共享)
進行轉變。 - T1,T2會以此的把指令從L3到L2到L1再到寄存器霜旧,進行計算错忱,然后回寫到L3中,因為對數(shù)據(jù)進行修改挂据,T1中的CPU需要對Cache line 進行 鎖定操作以清,鎖定完成之后把狀態(tài)更改為
M(修改)
狀態(tài),此時(i = 2 )
崎逃;當然T2也可以同時進行修改狀態(tài)為M(狀態(tài))
掷倔,具體看誰快,CPU彼此之間也是有時間延遲存在个绍。 - 當T1更改完成狀態(tài)之后勒葱,以此同時會發(fā)送一個消息到BUS(緩存一致性協(xié)議)中,通知其他的監(jiān)聽該內(nèi)存的Cache line障贸。
- 此時错森,CPU會有一個指令周期,去進行裁決Cache line的狀態(tài)篮洁。T2的Cache line監(jiān)聽到了數(shù)據(jù)變化
(i = 2 )
涩维,會把自身的狀態(tài)更新為I(Invaild)
狀態(tài),無法再更新數(shù)據(jù)(T2 i = 2)
到主內(nèi)存中袁波。 - 假如T2還想再更新數(shù)據(jù)到主內(nèi)存中瓦阐,需要重新的從主內(nèi)存中l(wèi)oad數(shù)據(jù)
(i = 2)
到CPU中,再重新計算ALU篷牌,然后回寫到主內(nèi)存中(i = 2 + 1)
Cache line 狀態(tài)失效場景
- 當
i
存儲長度大于一個Cache line的時候睡蟋,這個時候需要存儲到多個Cache line,這個時候是無法做到MESI緩存一致性協(xié)議的枷颊,只能用總線鎖戳杀。 - 當CPU不支持MESI
小結
回顧本章该面,我們了解到了計算機的模型,CPU信卡,內(nèi)存的交互通信工作流程隔缀,以及如何保證緩存一致性(MESI)等知識點。