溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java內(nèi)存模型以及線程安全的可見性問題是怎樣的

發(fā)布時間:2021-11-20 14:13:10 來源:億速云 閱讀:124 作者:柒染 欄目:大數(shù)據(jù)

這期內(nèi)容當中小編將會給大家?guī)碛嘘P(guān)Java內(nèi)存模型以及線程安全的可見性問題是怎樣的,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

Java內(nèi)存模型 VS JVM運行時數(shù)據(jù)區(qū)

首先Java內(nèi)存模型(JMM)和JVM運行時數(shù)據(jù)區(qū)并不是一個東西,許多介紹Java內(nèi)存模型的文章描述的堆,方法區(qū),Java虛擬機棧,本地方法棧,程序計數(shù)器這東西并不是Java內(nèi)存模型的內(nèi)容而是JVM運行時數(shù)據(jù)區(qū)的內(nèi)容。
要理解二者的區(qū)別就要了解《Java虛擬機規(guī)范》和《Java語言規(guī)范》。我們知道Java虛擬機上并不知只有Java語言,像JRuby, ,Scala,Kotlin,Groovy等也都運行在Java虛擬機上,而這些語言想要在Java虛擬機上運行就要遵守《Java虛擬機規(guī)范》,而JVM運行時數(shù)據(jù)區(qū)就是《Java虛擬機規(guī)范》的內(nèi)容。而《Java語言規(guī)范》就只是針對Java語言的規(guī)范,它對Java內(nèi)存模型做了詳細的描述。
Java內(nèi)存模型以及線程安全的可見性問題是怎樣的

什么是Java內(nèi)存模型(JMM)?

要了解Java內(nèi)存模型,首先要了解什么是內(nèi)存模型,之間在CPU緩存和內(nèi)存屏障 中我們了解到緩存一致性問題以及處理器優(yōu)化的指令重排序問題。為了保證并發(fā)編程中可以滿足原子性、可見性及有序性。有一個重要的概念,那就是——內(nèi)存模型。它解決了 CPU 多級緩存、處理器優(yōu)化、指令重排等導致的內(nèi)存訪問問題,保證了并發(fā)場景下的一致性、原子性和有序性。而Java內(nèi)存模型就是解決由于多線程通過共享內(nèi)存進行通信時,存在的本地內(nèi)存數(shù)據(jù)不一致、編譯器會對代碼指令重排序、處理器會對代碼亂序執(zhí)行等帶來的問題的一種規(guī)范。目的是保證并發(fā)編程場景中的原子性、可見性和有序性。
Java內(nèi)存模型可以分為線程棧(或者叫工作內(nèi)存,它是每個線程所獨有的)和堆(或者叫主內(nèi)存,與JVM運行時數(shù)據(jù)區(qū)的堆并不是一個概念,它是所線程共享的),其大致邏輯圖如下:
Java內(nèi)存模型以及線程安全的可見性問題是怎樣的

JMM中的具體內(nèi)容

Shared Variables定義

可以在線程之間共享的內(nèi)存稱為共享內(nèi)存或堆內(nèi)存
所有實例字段,靜態(tài)字段和數(shù)組元素都存儲在共享內(nèi)存,這些字段和數(shù)組就是共享變量
沖突:如果至少有一個訪問是寫操作,那么對同一個變量的兩次訪問是沖突的

這些能被多個線程訪問的共享變量是內(nèi)存模型規(guī)范的對象

線程間操作

線程間操作指一個線程執(zhí)行的操作可被其他線程感知或被其他線程直接影響
Java內(nèi)存模型只描述線程間操作,不描述線程內(nèi)操作,線程內(nèi)操作按照線程內(nèi)語義執(zhí)行
線程間操作有:

  • read操作(一般讀,即非volatile讀)

  • write操作(一般寫,即非volatile寫)

  • volatile read

  • volatile write

  • Lock,Unlock

  • 線程的第一個和最后一個操作

  • 外部操作

對同步規(guī)則的定義
  • 對volatile變量V的寫入,與所有其它線程后續(xù)對V的讀同步

  • 對于監(jiān)視器m的解鎖與所有后續(xù)操作對于m的加鎖同步

  • 對于每個屬性寫入默認值(0,false, null)與每個線程對其進行的操作同步

  • 啟動線程的操作與線程中的第一個操作同步

  • 線程T2的最后操作與線程T1發(fā)現(xiàn)T2已經(jīng)結(jié)束同步

  • 如果線程T1中斷了T2,那么線程T1的中斷操作與其他所有線程發(fā)現(xiàn)T2被中斷了同步

happens-before先行發(fā)生原則

happens-before關(guān)系用于描述兩個有沖突的動作之間的順序,如果一個action happens before 另一個action,則第一個操作對第二個操作可見,JVM需要實現(xiàn)如下happens-before規(guī)則:

  • 某個線程中的每個動作都happens-before該線程中該動作后面的操作

  • 某個管程中的unlock動作happens-before同一個管程上后續(xù)的lock操作

  • 對某個volatile字段的寫操作happens-before每個后續(xù)對該volatile字段的讀操作

  • 在某個對象上調(diào)用start()方法happens-before被啟動線程的任意動作

  • 如果在線程t1中成功執(zhí)行了t2.join(),則t2中的所有操作對t1可見

  • 如果某個動作a happens-before動作b,且b happens-before動作c,則a happens-before c

final在JMM中的處理

final在該對象的構(gòu)造函數(shù)中設(shè)置對象的字段,當線程看到該對象時,將始終看到該對象的final字段的正確構(gòu)造版本。如果在構(gòu)造函數(shù)中設(shè)置字段后發(fā)生讀取,則會看到該final字段分配的值,否則它將看到默認值。讀取該對象的final成員變量之前,先要讀取共享對象。
通常被 static final修飾的字段, 不能被修改。然而System.in, System.out, System.err被static final修飾卻可以修改,遺留問題,必須通過set方法改變,我們將這些字段稱為寫保護,以區(qū)別于普通final字段。

Word Tearing字節(jié)處理

有些處理器(尤其是早期的Alphas處理器)沒有提供寫單個字節(jié)的功能。在這樣的處理器上更新byte數(shù)組,若只是簡單的讀取整個內(nèi)容,更新對應的字節(jié),然后將整個內(nèi)容再寫回內(nèi)存,將是不合法的。這個問題有時候被稱為“字分裂(word tearing)”,更新字節(jié)有難度的處理器,就需要尋求其他方式來解決。因此,編程人員需要注意,盡量不要對byte[]中的元素進行重新賦值,更不要在多線程中這樣做。

可見性問題

可見性:主要是指一個線程對共享變量的寫入可以被后續(xù)另一個線程讀取到,也就說一個線程對共享變量的操作對另一個線程是可見的。
而可見性問題就是指一個線程對共享變量進行了寫入而其他的線程卻無法讀取到該線程寫入的結(jié)果,根據(jù)以下工作內(nèi)存的緩存的模型我們可以知道,造成可見性的問題主要有兩方面,一個是數(shù)據(jù)在寫入的時候只是寫入了緩存而沒有寫入主內(nèi)存,一個是數(shù)據(jù)在讀取的時候只是從緩存中讀取到了數(shù)據(jù)而沒有從主內(nèi)存讀取數(shù)據(jù)。
Java內(nèi)存模型以及線程安全的可見性問題是怎樣的

可見性問題的解決方法 — volatile關(guān)鍵字

volatile關(guān)鍵字可以保證一個線程對共享變量的修改,能夠及時的被其他線程看到。
根據(jù)JMM中的happen before 和同步原則:

  • 對某個volatile字段的寫操作happens-before每個后續(xù)對該volatile字段的讀操作

  • 對volatile變量V的寫入,與所有其它線程后續(xù)對V的讀同步


    而要滿足這些條件volatile關(guān)鍵字就具有以下功能:

  • 禁止緩存,volatile變量的訪問控制符會加個ACC_VOLATILE,《Java虛擬機規(guī)范》 中的對它的描述就是“cannot be cached”

  • 對volatile變量相關(guān)的指令不做重排序

上述就是小編為大家分享的Java內(nèi)存模型以及線程安全的可見性問題是怎樣的了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關(guān)知識,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細節(jié)

免責聲明:本站發(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)容。

AI