真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Java內(nèi)存模型的工作模式是什么

這篇文章主要介紹“Java內(nèi)存模型的工作模式是什么”,在日常操作中,相信很多人在Java內(nèi)存模型的工作模式是什么問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Java內(nèi)存模型的工作模式是什么”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!

目前成都創(chuàng)新互聯(lián)已為1000多家的企業(yè)提供了網(wǎng)站建設(shè)、域名、雅安服務(wù)器托管綿陽服務(wù)器托管、企業(yè)網(wǎng)站設(shè)計、柴桑網(wǎng)站維護等服務(wù),公司將堅持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長,共同發(fā)展。

引入緩存

現(xiàn)代計算機中,CPU的指令速度遠超內(nèi)存的存取速度,由于CPU和內(nèi)存的運算速度有幾個數(shù)量級的差距,所以現(xiàn)代計算機系統(tǒng)加入一層讀寫速度盡可能接近CPU運算速度的高速緩存(Cache)來作為內(nèi)存與處理器之間的緩沖,將運算需要使用到的數(shù)據(jù)復(fù)制到緩存中,CPU運算操作的是內(nèi)存數(shù)據(jù)的副本,當(dāng)運算結(jié)束后再從緩存將副本數(shù)據(jù)同步回內(nèi)存之中,這樣處理器就無須等待緩慢的內(nèi)存讀寫了。

讀取緩存

當(dāng)CPU要讀取一個數(shù)據(jù)時,首先從一級緩存中查找,如果沒有找到再從二級緩存中查找,如果還是沒有就從三級緩存或內(nèi)存中查找。

SMP結(jié)構(gòu)組成

Java內(nèi)存模型的工作模式是什么

計算機在運行中,先從內(nèi)存中取出第一條指令,通過控制器譯碼,按照指令的要求從存儲器中取出數(shù)據(jù)進行制定的邏輯運算后再按照內(nèi)存地址把結(jié)果寫回內(nèi)存中,接著再取出來第二條指令,依次遍歷執(zhí)行下去。

SMP邏輯結(jié)構(gòu)(cpu與緩存的一致性)

Java內(nèi)存模型的工作模式是什么

  • 單線程CPU核心緩存只被一個線程訪問。緩存獨占,不會出現(xiàn)訪問沖突問題。

  • 單核 CPU,多線程:進程中的多個線程會同時訪問進程中的共享數(shù)據(jù),CPU 將某塊內(nèi)存加載到緩存后,不同線程在訪問相同的物理地址的時候,都會映射到相同的緩存位置,這樣即使發(fā)生線程的切換,緩存仍然不會失效,何時候只有一個線程在執(zhí)行,不會發(fā)生訪問沖突的問題。

  • 多核 CPU,多線程:每個核都至少有一個 L1 緩存。多個線程訪問進程中的某個共享內(nèi)存,且這多個線程分別在不同的核心上執(zhí)行,則每個核心都會在各自的Cache中保留一份共享內(nèi)存的緩沖,由于多核是可以并行的,可能會出現(xiàn)多個線程同時寫各自的緩存的情況,而各自的 Cache 之間的數(shù)據(jù)就有不一致性的問題(并發(fā)導(dǎo)致的根源問題)。

CPU多核緩存架構(gòu)(MESI的實現(xiàn))

為了解決這個問題,需要各個處理器訪問緩存時都遵循一些協(xié)議,在讀寫時要根據(jù)協(xié)議來進行操作,這個協(xié)議就是MESI協(xié)議(緩存一致性協(xié)議) Java內(nèi)存模型的工作模式是什么

  1. 在不同的硬件生產(chǎn)商和不同的操作系統(tǒng)下,內(nèi)存的訪問邏輯有一定的差異,結(jié)果就是當(dāng)你的代碼在某個系統(tǒng)環(huán)境下運行良好,并且線程安全但是換了個系統(tǒng)就出現(xiàn)各種問題;

  2. 這是因為不同的處理器,在處理器優(yōu)化指令重排等方面存在差異,造成同樣的代碼,在經(jīng)過不同的處理器優(yōu)化和指令重排后,最后執(zhí)行出來的結(jié)果可能不同,這是我們所不能接受的。

  3. JMM就應(yīng)運而生了,究其根本就是為了解決在并發(fā)環(huán)境下,保證數(shù)據(jù)的安全,滿足場景的可見性、原子性、有序性。

狀態(tài)描述監(jiān)聽任務(wù)
M 修改 (Modified)該Cache line有效,數(shù)據(jù)被修改了,和內(nèi)存中的數(shù)據(jù)不一致,數(shù)據(jù)只存在于本Cache中。緩存行必須時刻監(jiān)聽所有試圖讀該緩存行相對就主存的操作,這種操作必須在緩存將該緩存行寫回主存并將狀態(tài)變成S(共享)狀態(tài)之前被延遲執(zhí)行。
E 獨享(Exclusive)該Cache line有效,數(shù)據(jù)和內(nèi)存中的數(shù)據(jù)一致,數(shù)據(jù)只存在于本Cache中。緩存行也必須監(jiān)聽其它緩存讀主存中該緩存行的操作,一旦有這種操作,該緩存行需要變成S(共享)狀態(tài)。
S 共享 (Shared)該Cache line有效,數(shù)據(jù)和內(nèi)存中的數(shù)據(jù)一致,數(shù)據(jù)存在于很多Cache中。緩存行也必須監(jiān)聽其它緩存使該緩存行無效或者獨享該緩存行的請求,并將該緩存行變成無效(Invalid)。
I 無效 (Invalid)該Cache line無效。

CPU線程切換導(dǎo)致原子性問題(原子性)

原子性把一個操作或者多個操作視為一個整體,在執(zhí)行的過程不能被中斷的特性叫原子性。

  • 為了最大化的利用CPU,CPU采用時間片的方式,切換線程執(zhí)行。而在切換線程的過程中會導(dǎo)致原子性問題

指令重排序問題(有序性)

進程和線程的本質(zhì)是增加并行/并發(fā)的任務(wù)數(shù)量來提高CPU的執(zhí)行效率,緩存的本質(zhì)是通過減少IO時間來提升CPU的利用率


  1. CPU指令優(yōu)化的初衷就是想通過調(diào)整CPU指令的執(zhí)行順序或異步化的操作來提升CPU執(zhí)行指令的效率。

  2. 為了使得處理器內(nèi)部的運算單元能盡量被充分利用,處理器可能會對輸入代碼進行亂序執(zhí)行優(yōu)化,處理器會在計算之后將亂序執(zhí)行的結(jié)果重組,優(yōu)化原則是保證重排序后不影響單線程執(zhí)行結(jié)果(As If Serial)

  3. 重排序的大體邏輯就是優(yōu)先把CPU比較耗時的指令放到最先執(zhí)行,然后在這些指令執(zhí)行的空余時間來執(zhí)行其他指令。**Java虛擬機的即時編譯器中也有類似的指令重排序優(yōu)化。

編譯操作-(語義優(yōu)化)指令重排->處理器級別重排(指令優(yōu)化)->內(nèi)存玉華指令重排(內(nèi)存分析優(yōu)化)


內(nèi)存模型

為了保證共享內(nèi)存使用的正確性(原子性、有序性、可見性),內(nèi)存模型定義了共享內(nèi)存中多線程讀寫操作的規(guī)范。通過這些規(guī)則來規(guī)范對主內(nèi)存的讀寫,從而保障指令的正確執(zhí)行。

解決了CPU多級緩存、處理器優(yōu)化、指令重排等導(dǎo)致的內(nèi)存訪問問題,保證了并發(fā)場景下的一致性、原子性和有序性。

Java內(nèi)存模型(JMM)

JMM是一種規(guī)范,目的是解決由于多線程通過共享內(nèi)存進行通信時,存在的工作內(nèi)存數(shù)據(jù)不一致、編譯器對代碼指令重排序、處理器對代碼亂序執(zhí)行、CPU切換線程等帶來的問題。

  • JMM從java 5開始的JSR-133發(fā)布后,就比較成熟完善了;

Java內(nèi)存模型的工作模式是什么

JMM是符合內(nèi)存模型規(guī)范的,屏蔽了各種硬件和操作系統(tǒng)的訪問差異的,保證了Java程序在各種平臺下對內(nèi)存的訪問都能保證效果一致的機制。(如同JVM一樣標(biāo)準規(guī)范)。

Java線程內(nèi)存模型規(guī)定:

  1. 所有的變量都存儲在主內(nèi)存中,每條線程還有自己的工作內(nèi)存,線程的工作內(nèi)存中保存了該線程中是用到的變量的主內(nèi)存副本拷貝,線程對變量的所有操作都必須在工作內(nèi)存中進行,而不能直接讀寫主內(nèi)存。

  2. 不同的線程之間也無法直接訪問對方工作內(nèi)存中的變量,線程間變量的傳遞均需要自己的工作內(nèi)存和主存之間進行數(shù)據(jù)同步進行,也規(guī)定了如何做數(shù)據(jù)同步以及什么時候做數(shù)據(jù)同步。

內(nèi)存交互操作

內(nèi)存交互操作有8種,虛擬機實現(xiàn)必須保證每一個操作都是原子的,不可在分的:

  • lock(鎖定):作用于主內(nèi)存的變量,把一個變量標(biāo)識為線程獨占狀態(tài)

  • unlock(解鎖):作用于主內(nèi)存的變量,它把一個處于鎖定狀態(tài)的變量釋放出來,釋放后的變量才可以被其他線程鎖定

  • read(讀取):作用于主內(nèi)存變量,它把一個變量的值從主內(nèi)存?zhèn)鬏數(shù)骄€程的工作內(nèi)存中,以便隨后的load動作使用

  • load(載入):作用于工作內(nèi)存的變量,它把read操作從主存中變量放入工作內(nèi)存中;

  • use(使用):作用于工作內(nèi)存中的變量,它把工作內(nèi)存中的變量傳輸給執(zhí)行引擎,每當(dāng)虛擬機遇到一個需要使用到變量的值,就會使用到這個指令

  • assign(賦值):作用于工作內(nèi)存中的變量,它把一個從執(zhí)行引擎中接受到的值放入工作內(nèi)存的變量副本中

  • store(存儲):作用于主內(nèi)存中的變量,它把一個從工作內(nèi)存中一個變量的值傳送到主內(nèi)存中,以便后續(xù)的write使用

  • write(寫入):作用于主內(nèi)存中的變量,它把store操作從工作內(nèi)存中得到的變量的值放入主內(nèi)存的變量中

JMM對這八種指令的使用,制定了如下規(guī)則:

  1. 不允許read和load、store和write操作之一單獨出現(xiàn)即使用了read必須load,使用了store必須write

  2. 不允許線程丟棄他最近的assign操作,即工作變量的數(shù)據(jù)改變了之后,必須告知主存,不允許一個線程將沒有assign的數(shù)據(jù)從工作內(nèi)存同步回主內(nèi)存。

  3. 一個新的變量必須在主內(nèi)存中誕生,不允許工作內(nèi)存直接使用一個未被初始化的變量。就是對變量實施use、store操作之前,必須經(jīng)過load、assign操作

  4. 一個變量同一時間只有一個線程能對其進行l(wèi)ock。多次lock后,必須執(zhí)行相同次數(shù)的unlock才能解鎖。

  5. 如果對一個變量進行l(wèi)ock操作,會清空所有工作內(nèi)存中此變量的值,在執(zhí)行引擎使用這個變量前,必須重新load或assign操作初始化變量的值。

  6. 如果一個變量沒有被lock,就不能對其進行unlock操作。也不能unlock一個被其他線程鎖住的變量。

  7. 對一個變量進行unlock操作之前,必須把此變量同步回主內(nèi)存。

Java內(nèi)存模型的工作模式是什么

特征

可見性

是指當(dāng)多個線程訪問同一個變量時,一個線程修改了這個變量的值,其他線程能夠立即看得到修改的值;

Java可見性,可以使用 volatile 關(guān)鍵字,那就是被其修飾的變量在被修改后會立即同步到主內(nèi)存(其實也是要反應(yīng)時間的)主要靠內(nèi)存屏障;

Java內(nèi)存模型的工作模式是什么

Java 中的 Synchronized 和 Final 兩個關(guān)鍵字也可以實現(xiàn)可見性;

原子性

  • 是指在一個操作中被當(dāng)作一個整體,要么一起執(zhí)行,要么就不執(zhí)行;

  • 為了保證原子性,Java提供了兩個高級的字節(jié)碼指令 MonitorenterMonitorexit,對應(yīng)的關(guān)鍵字就是 Synchronized;

有序性

  • 程序執(zhí)行的順序按照代碼的先后順序執(zhí)行;

  • 可以使用 synchronized 和 volatile 來保證多線程之間操作的有序性,只是兩者實現(xiàn)的方式不一樣,volatile 關(guān)鍵字會禁止指令重排,synchronized 關(guān)鍵字保證同一時刻只允許一條線程操作;

到這里,我們似乎發(fā)現(xiàn)了,Synchronized 好像可以同時滿足三種特征,這也是Synchronized 被用的很頻繁的原因,但是 Synchronized 是比較影響性能的,雖然編譯器提供了很多鎖優(yōu)化技術(shù),但是也不建議過度使用。

Happen-Before 規(guī)則

分析一個并發(fā)程序是否安全,更多時候其實都依賴Happen-Before原則進行分析。

就是當(dāng)A操作先行發(fā)生于B操作,則在發(fā)生B操作的時候,操作A產(chǎn)生的影響能被B觀察到,“影響”包括修改了內(nèi)存中的共享變量的值、發(fā)送了消息、調(diào)用了方法等;

  • 程序次序規(guī)則(Program Order Rule):在一個線程內(nèi),程序的執(zhí)行規(guī)則跟程序的書寫規(guī)則是一致的,從上往下執(zhí)行。

  • 管程鎖定規(guī)則(Monitor Lock Rule):一個Unlock的操作肯定先于下一次Lock的操作。這里必須是同一個鎖。同理我們可以認為在synchronized同步同一個鎖的時候,鎖內(nèi)先行執(zhí)行的代碼,對后續(xù)同步該鎖的線程來說是完全可見的。

  • volatile變量規(guī)則(volatile Variable Rule):對同一個volatile的變量,先行發(fā)生的寫操作,肯定早于后續(xù)發(fā)生的讀操作

  • 線程啟動規(guī)則(Thread Start Rule):Thread對象的start()方法先行發(fā)生于此線程的沒一個動作

  • 線程中止規(guī)則(Thread Termination Rule):Thread對象的中止檢測(如:Thread.join(),Thread.isAlive()等)操作,必行晚于線程中所有操作

  • 線程中斷規(guī)則(Thread Interruption Rule):對線程的interruption()調(diào)用,先于被調(diào)用的線程檢測中斷事件(Thread.interrupted())的發(fā)生

  • 對象中止規(guī)則(Finalizer Rule):一個對象的初始化方法先于一個方法執(zhí)行Finalizer()方法

  • 傳遞性(Transitivity):如果操作A先于操作B、操作B先于操作C,則操作A先于操作C

到此,關(guān)于“Java內(nèi)存模型的工作模式是什么”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>
新聞標(biāo)題:Java內(nèi)存模型的工作模式是什么
本文網(wǎng)址:http://weahome.cn/article/pgicie.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部