Ⅰ java多線程的內存模型
硬體的內存模型
物理機並發處理的方案對於jvm的內存模型實現,也有很大的參考作用,畢竟jvm也是在硬體層上來做事情,底層架構也決定了上層的建築建模方式。
計算機並發並非只是多個處理器都參與進來計算就可以了,會牽扯到一些列硬體的問題,最直接的就是要和內存做交互。但計算機的存儲設備與處理器的預算速度相差太大,完全不能滿足處理器的處理速度,怎麼辦,這就是後續加入的一層讀寫速度接近處理器運算速度的高速緩存來作為處理器和內存之間的緩沖。
高速緩存一邊把使用的數據,從內存復制搬入,方便處理器快速運算,一邊把運算後的數據,再同步到主內存中,如此處理器就無需等待了。
高速緩存雖然解決了處理器和內存的矛盾,但也為計算機帶來了另一個問題:緩存一致性。特別是當多個處理器都涉及到同一塊主內存區域的時候,將可能會導致各自的緩存數據不一致。
那麼出現不一致情況的時候,以誰的為准?
為了解決這個問題,處理器和內存之間的讀寫的時候需要遵循一定的協議來操作,這類協議有:MSI、MESI、MOSI、Synapse、Firefly以及DragonProtocol等。這就是上圖中處理器、高速緩存、以及內存之間的處理方式。
另外除了高速緩存之外,為了充分利用處理器,處理器還會把輸入的指令碼進行亂序執行優化,只要保證輸出一致,輸入的信息可以亂序執行重組,所以程序中的語句計算順序和輸入代碼的順序並非一致。
JVM內存模型
上面我們了解了硬體的內存模型,以此為借鑒,我們看看jvm的內存模型。
jvm定義的一套java內存模型為了能夠跨平台達到一致的內存訪問效果,從而屏蔽掉了各種硬體和操作系統的內存訪問差異。這點和c和c++並不一樣,C和C++會直接使用物理硬體和操作系統的內存模型來處理,所以在各個平台上會有差異,這一點java不會。
java的內存模型規定了所有的變數都存儲在主內存中,java課程發現每個線程擁有自己的工作內存,工作內存保存了該線程使用到的變數的主內存拷貝,線程對變數所有操作,讀取,賦值,都必須在工作內存中進行,不能直接寫主內存變數,線程間變數值的傳遞均需要主內存來完成。
Ⅱ Java學習——volatitle關鍵字
內存模型的概念與作用
在計算機執行程序時,指令在CPU中執行,涉及數據讀取和寫入。數據存放在主存(物理內存),這會導致速度差異,因此CPU有高速緩存。程序運行時,數據從主存復制到高速緩存,CPU直接從緩存讀取和寫入,運算結束後刷新緩存到主存。多線程中,高速緩存間的數據不一致即為緩存一致性問題。共享變數是多線程訪問的變數,可能引發問題。
解決緩存不一致的策略有:在匯流排上加LOCK#鎖,或使用緩存一致性協議(如Intel的MESI協議)。LOCK#鎖阻塞其他CPU訪問內存,MESI協議確保緩存副本一致性。
並發編程中的關鍵概念
並發編程中面臨原子性、可見性與有序性問題。原子性指操作要麼全部執行,要麼不執行。可見性指多線程修改變數值後,其他線程能立即看到修改。有序性指指令按代碼順序執行。
Java內存模型概述
Java內存模型通過規范定義變數訪問規則,屏蔽硬體和操作系統差異,確保跨平台一致性。模型規定所有變數在主存,每個線程有工作內存。線程操作在工作內存,不能直接操作主存,且不能訪問其他線程工作內存。
Java內存模型保證:基本讀取和賦值原子性;通過volatile關鍵字保證可見性;synchronized和Lock保證有序性。
volatile關鍵字的特性與局限
volatile關鍵字提供兩層語義:保證不同線程對變數操作的可見性,禁止指令重排序。其局限在於不能保證操作原子性。
自增操作的原子性問題
volatile關鍵字保證可見性,但無法保證操作原子性。自增操作可能被分割執行,導致不一致結果。Java並發包提供原子操作類,利用CAS(Compare And Swap)實現原子性。
volatile的指令重排序限制
volatile關鍵字禁止指令重排序,確保在讀或寫操作前,前操作更改可見;寫操作後,後續操作未執行。這在一定程度上保證了有序性。
總結
理解內存模型、並發問題與Java內存模型對於編寫高效、一致的並發代碼至關重要。利用volatile、synchronized與Lock關鍵字可有效管理原子性、可見性與有序性,確保多線程程序的正確性與性能。