您好,登錄后才能下訂單哦!
這篇文章主要講解了“Java內(nèi)存模型和volatile關(guān)鍵字怎么掌握”,文中的講解內(nèi)容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Java內(nèi)存模型和volatile關(guān)鍵字怎么掌握”吧!
java內(nèi)存模型(JMM):
相關(guān)概念: 1)在命令式編程中,線程之間的通信機制有兩種:共享內(nèi)存和消息傳遞。 2)java的并發(fā)采用的是共享內(nèi)存模型:通過讀/寫內(nèi)存中的公共狀態(tài)進行隱式通信。 概念:java線程之間的通信是由java內(nèi)存模型控制的,JMM決定一個線程對共享變量的寫入何時對另一個線程可見。 說明: 1>線程之間的共享變量存儲在主內(nèi)存中,每個線程都有一個私有的工作內(nèi)存,工作內(nèi)存中存儲了該線程讀/寫共享變量的副本。 2>工作內(nèi)存是JMM的一個抽象概念,并不真實存在。它涵蓋了緩存、寫緩沖區(qū)、寄存器以及其他的硬件和編譯器優(yōu)化。 3>線程對變量的所有操作(讀取、賦值等)都必須在工作內(nèi)存中進行,而不能直接讀寫主內(nèi)存中的變量。 4>不同的線程之間也無法直接訪問對方工作內(nèi)存中的變量,線程間變量值的傳遞均需要通過主內(nèi)存來完成。
volatile關(guān)鍵字:
相關(guān)概念: 緩存行:緩存器中可以分配的最小存儲單位。 L1緩存:內(nèi)部緩存。 L2緩存:外部緩存。 原理: 1)為了提高處理速度,處理器不直接和內(nèi)存進行通信,而是先將系統(tǒng)內(nèi)存中的數(shù)據(jù)讀到緩存(L1、L2)后再進行操作,但操作完成后,處理器是不知道何時要把操作后的數(shù)據(jù)寫回到內(nèi)存中。 2)對volatile修飾的變量進行寫操作時,JVM會向處理器發(fā)送一條Lock前綴的指令,將這個變量所在緩存行(即JMM中的工作內(nèi)存)的數(shù)據(jù)寫回到系統(tǒng)內(nèi)存中,并且將其它CPU里緩存了該內(nèi)存地址的數(shù)據(jù)無效。 補充: 1>對volatile修飾的變量進行寫操作(賦值)時,在JIT編譯器生成的匯編指令中,我們會發(fā)現(xiàn)有一個以Lock為前綴的指令。 2>以Lock為前綴的指令在多核處理器下會引發(fā)了兩件事情:①將當前處理器緩存行的數(shù)據(jù)寫回到系統(tǒng)內(nèi)存中 ②這個寫回內(nèi)存的操作會導致其它CPU里緩存了該內(nèi)存地址的數(shù)據(jù)無效。 volatile的內(nèi)存原語: 當讀一個volatile變量時,JMM會把該線程對應(yīng)的工作內(nèi)存置為無效,線程接下來將從主內(nèi)存中讀取共享變量。 當寫一個volatile變量時,JMM會把該線程對應(yīng)的工作內(nèi)存中的共享變量值刷新到主內(nèi)存。 即: 1將本地內(nèi)存中的數(shù)據(jù)設(shè)置為無效, 2從主內(nèi)存中將數(shù)據(jù)復制到本地內(nèi)存中, 3在本地內(nèi)存中進行操作, 4操作完成后將本地內(nèi)存中的數(shù)據(jù)刷新到主內(nèi)存中。整體看起來就像是直接在主內(nèi)存中操作一樣。 說明: 用volatile修飾的變量如果被一個線程更改了,那么其它的線程都會立即感知,并且每個線程獲取該變量的值都是最新的值,訪問volatile修飾的變量看起來就像是直接在內(nèi)存中讀寫一樣。 特性: 可見性:對一個volatile變量的讀,(任意線程)總是能看到對這個volatile變量最后的寫入。 原子性:對一個volatile變量的讀/寫具有原子性,但類似于volatile++這種復合操作不具有原子性。 優(yōu)點: 不會引起線程上下文的切換 volatile與synchronized的比較: 1)關(guān)鍵字volatile只能修飾變量,synchronized可以修飾代碼塊、方法 2)volatile不能保證原子性,synchronized保證原子性: volatile可以保證數(shù)據(jù)的可見性,但是不能保證原子性,所以volatile解決的是變量在多線程之間的可見性; synchronized可以保證原子性,也保證了可見性(synchronized會將私有內(nèi)存和公共內(nèi)存中的數(shù)據(jù)做同步),所以synchronized解決的是多線程之間訪問資源的同步性。
重排序:
說明:在執(zhí)行程序時,為了提高性能,編譯器和處理器常常會對指令做重排序。 重排序分2種類型: 1)編譯器重排序:編譯器在不改變單線程程序語義的前提下,可以重新安排語句的執(zhí)行順序。 2)處理器重排序: 1>指令級并行的重排序:現(xiàn)代處理器采用了指令級并行技術(shù)來將多條指令重疊執(zhí)行。如果不存在數(shù)據(jù)依賴性,處理器可以改變語句對應(yīng)機器指令的執(zhí)行順序。 2>內(nèi)存系統(tǒng)的重排序: 由于處理器使用緩存和讀/寫緩沖區(qū),這使得加載和存儲操作看上去可能是在亂序執(zhí)行。 JMM如何實現(xiàn)volatile寫/讀的內(nèi)存語義: 1)JMM針對編譯器制定的volatile重排序規(guī)則: 兩個操作間重排序的條件: 1>當?shù)谝粋€操作是volatile讀,不管第二個操作是什么,都不能重排序。這個規(guī)則確保volatile讀之后的操作不會被編譯器重排序到volatile讀之前。 2>當?shù)诙€操作是volatile寫,不管第一個操作是什么,都不能重排序。這個規(guī)則確保volatile寫之前的操作不會被編譯器重排序到volatile寫之后。 3>當?shù)谝粋€操作是volatile寫,第二個操作是volatile讀時,不能重排序。 由以上3點可以得出結(jié)論:兩個volatile變量操作不能夠進行重排序。 2)為了實現(xiàn)volatile的內(nèi)存語義,編譯器在生成字節(jié)碼時,會在指令序列中插入內(nèi)存屏障來禁止特定類型的處理器重排序。(內(nèi)存屏障:將前面操作的共享變量值刷新到主內(nèi)存中。)
感謝各位的閱讀,以上就是“Java內(nèi)存模型和volatile關(guān)鍵字怎么掌握”的內(nèi)容了,經(jīng)過本文的學習后,相信大家對Java內(nèi)存模型和volatile關(guān)鍵字怎么掌握這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關(guān)知識點的文章,歡迎關(guān)注!
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。