中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

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

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

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

發布時間:2021-11-20 14:13:10 來源:億速云 閱讀:127 作者:柒染 欄目:大數據

這期內容當中小編將會給大家帶來有關Java內存模型以及線程安全的可見性問題是怎樣的,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

Java內存模型 VS JVM運行時數據區

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

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

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

JMM中的具體內容

Shared Variables定義

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

這些能被多個線程訪問的共享變量是內存模型規范的對象

線程間操作

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

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

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

  • volatile read

  • volatile write

  • Lock,Unlock

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

  • 外部操作

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

  • 對于監視器m的解鎖與所有后續操作對于m的加鎖同步

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

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

  • 線程T2的最后操作與線程T1發現T2已經結束同步

  • 如果線程T1中斷了T2,那么線程T1的中斷操作與其他所有線程發現T2被中斷了同步

happens-before先行發生原則

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

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

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

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

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

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

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

final在JMM中的處理

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

Word Tearing字節處理

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

可見性問題

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

可見性問題的解決方法 — volatile關鍵字

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

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

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


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

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

  • 對volatile變量相關的指令不做重排序

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

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

呼和浩特市| 平原县| 儋州市| 汨罗市| 志丹县| 翁牛特旗| 烟台市| 衡南县| 金华市| 原阳县| 上饶市| 娄烦县| 正宁县| 监利县| 敦化市| 九寨沟县| 泸水县| 蒙阴县| 东乌| 石门县| 分宜县| 龙井市| 桂林市| 溆浦县| 军事| 公主岭市| 新安县| 三门县| 七台河市| 娄烦县| 平湖市| 五峰| 吉隆县| 新化县| 时尚| 巴林右旗| 城步| 开远市| 鄂托克前旗| 晋宁县| 北票市|