一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - Java并發之原子性 有序性 可見性及Happen Before原則

Java并發之原子性 有序性 可見性及Happen Before原則

2022-01-13 10:25沒頭腦遇到不高興 Java教程

一提到happens-before原則,就讓人有點“丈二和尚摸不著頭腦”。這個涵蓋了整個JMM中可見性原則的規則,究竟如何理解,把我個人一些理解記錄下來。下面可以和小編一起學習Java 并發四個原則

1.原子性(Atomicity)

原子性指的是一個操作是不可中斷的,即使是在多線程環境下,一個操作一旦開始就不會被其他線程影響。由Java內存模型來直接保證的原子性變量操作包括read、load、assign、use、store和write這六個,我們大致可以認為,基本數據類型的訪問、讀寫都是具備原子性的(例外就是long和double的非原子性協定)。如果應用場景需要一個更大范圍的原子性保證(經常會遇到),Java內存模型還提供了lock和unlock操作來滿足這種需求,盡管虛擬機未把lock和unlock操作直接開放給用戶使用,但是卻提供了更高層次的字節碼指令monitorenter和monitorexit來隱式地使用這兩個操作。這兩個字節碼指令反映到Java代碼中就是同步塊——synchronized關鍵字,因此在synchronized塊之間的操作也具備原子性。

long和double的非原子性協定”(Non-Atomic Treatment of double and long Variables):

在java中,對基本數據類型的變量的讀取和賦值操作是原子性操作有點要注意的是,對于32位系統的來說,long類型數據和double類型數據(對于基本數據類型,byte, short, int, float, boolean, char讀寫是原子操作),它們的讀寫并非原子性的,也就是說如果存在兩條線程同時對long類型或者double類型的數據進行讀寫是存在相互干擾的,因為對于32位虛擬機來說,每次原子讀寫是32位的,而long和double則是64位的存儲單元,這樣會導致一個線程在寫時,操作完前32位的原子操作后,輪到B線程讀取時,恰好只讀取到了后32位的數據,這樣可能會讀取到一個既非原值又不是線程修改值的變量,它可能是“半個變量”的數值,即64位數據被兩個線程分成了兩次讀取。但也不必太擔心,因為讀取到“半個變量”的情況比較少見,至少在目前的商用的虛擬機中,幾乎都把64位的數據的讀寫操作作為原子操作來執行。

  • X=10; //原子性(簡單的讀取、將數字賦值給變量)
  • Y = x; //變量之間的相互賦值,不是原子操作
  • X++; //對變量進行計算操作
  • X = x+1;

2.可見性(Visibility)

可見性就是指當一個線程修改了共享變量的值時,其他線程能夠立即得知這個修改。上文在講解volatile變量的時候我們已詳細討論過這一點。Java內存模型是通過在變量修改后將新值同步回主內存,在變量讀取前從主內存刷新變量值這種依賴主內存作為傳遞媒介的方式來實現可見性的,無論是普通變量還是volatile變量都是如此。普通變量與volatile變量的區別是,volatile的特殊規則保證了新值能立即同步到主內存,以及每次使用前立即從主內存刷新。因此我們可以說volatile保證了多線程操作時變量的可見性,而普通變量則不能保證這一點。

除了volatile之外,Java還有兩個關鍵字能實現可見性,它們是synchronized和final。同步塊的可見性是由“對一個變量執行unlock操作之前,必須先把此變量同步回主內存中(執行store、write操作)”這條規則獲得的。而final關鍵字的可見性是指:被final修飾的字段在構造器中一旦被初始化完成,并且構造器沒有把“this”的引用傳遞出去(this引用逃逸是一件很危險的事情,其他線程有可能通過這個引用訪問到“初始化了一半”的對象),那么在其他線程中就能看見final字段的值。

如下面所示,變量i與j都具備可見性,它們無須同步就能被其他線程正確訪問。

?
1
2
3
4
5
6
7
8
9
10
11
public static final int i;
public final int j;
static {
    i = 0;
    // 省略后續動作
}
{
    // 也可以選擇在構造函數中初始化
    j = 0;
    // 省略后續動作
}

3.有序性(Ordering)

Java內存模型的有序性在前面講解volatile時也比較詳細地討論過了,Java程序中天然的有序性可以總結為一句話:如果在本線程內觀察,所有的操作都是有序的;如果在一個線程中觀察另一個線程,所有的操作都是無序的。前半句是指“線程內似表現為串行的語義”(Within-Thread As-If-Serial Semantics),后半句是指“指令重排序”現象和“工作內存與主內存同步延遲”現象。Java語言提供了volatile和synchronized兩個關鍵字來保證線程之間操作的有序性,volatile關鍵字本身就包含了禁止指令重排序的語義,而synchronized則是由“一個變量在同一個時刻只允許一條線程對其進行lock操作”這條規則獲得的,這個規則決定了持有同一個鎖的兩個同步塊只能串行地進入。

volatile用來保證可見性和有序性,synchronized則對三種特性都可以保證。

4.happens-before(先行發生)原則

只靠sychronized和volatile關鍵字來保證原子性、可見性以及有序性,那么編寫并發程序可能會顯得十分麻煩,幸運的是,從JDK 5開始,Java使用新的JSR-133內存模型,提供了
happens-before 原則來輔助保證程序執行的原子性、可見性以及有序性的問題,它是判斷數據是否存在競爭、線程是否安全的依據。

先行發生是Java內存模型中定義的兩項操作之間的偏序關系,比如說操作A先行發生于操作B,其實就是說在發生操作B之前,操作A產生的影響能被操作B觀察到,“影響”包括修改了內存中共享變量的值、發送了消息、調用了方法等。下面三個偽代碼:

?
1
2
3
4
5
6
// 以下操作在線程A中執行
i = 1;
// 以下操作在線程B中執行
j = i;
// 以下操作在線程C中執行
i = 2;

假設線程A中的操作“i=1”先行發生于線程B的操作“j=i”,那我們就可以確定在線程B的操作執行后,變量j的值一定是等于1,得出這個結論的依據有兩個:一是根據先行發生原則,“i=1”的結果可以被觀察到;二是線程C還沒登場,線程A操作結束之后沒有其他線程會修改變量i的值。現在再來考慮線程C,我們依然保持線程A和B之間的先行發生關系,而C出現在線程A和B的操作之間,但是C與B沒有先行發生關系,那j的值會是多少呢?答案是不確定!1和2都有可能,因為線程C對變量i的影響可能會被線程B觀察到,也可能不會,這時候線程B就存在讀取到過期數據的風險,不具備多線程安全性。

下面是Java內存模型下一些“天然的”先行發生關系,這些先行發生關系無須任何同步器協助就已經存在,可以在編碼中直接使用。如果兩個操作之間的關系不在此列,并且無法從下列規則推導出來,則它們就沒有順序性保障,虛擬機可以對它們隨意地進行重排序。

  • 程序次序規則(Program Order Rule):在一個線程內,按照控制流順序,書寫在前面的操作先行發生于書寫在后面的操作。注意,這里說的是控制流順序而不是程序代碼順序,因為要考慮分支、循環等結構。
  • 管程鎖定規則(Monitor Lock Rule):一個unlock操作先行發生于后面對同一個鎖的lock操作。這里必須強調的是“同一個鎖”,而“后面”是指時間上的先后。
  • volatile變量規則(Volatile Variable Rule):對一個volatile變量的寫操作先行發生于后面對這個變量的讀操作,這里的“后面”同樣是指時間上的先后。
  • 線程啟動規則(Thread Start Rule):Thread對象的start()方法先行發生于此線程的每一個動作。
  • 線程終止規則(Thread Termination Rule):線程中的所有操作都先行發生于對此線程的終止檢測,我們可以通過Thread::join()方法是否結束、Thread::isAlive()的返回值等手段檢測線程是否已經終止執行。
  • 線程中斷規則(Thread Interruption Rule):對線程interrupt()方法的調用先行發生于被中斷線程的代碼檢測到中斷事件的發生,可以通過Thread::interrupted()方法檢測到是否有中斷發生。
  • 對象終結規則(Finalizer Rule):一個對象的初始化完成(構造函數執行結束)先行發生于它的finalize()方法的開始。
  • 傳遞性(Transitivity):如果操作A先行發生于操作B,操作B先行發生于操作C,那就可以得出操作A先行發生于操作C的結論。

一個操作“時間上的先發生”不代表這個操作會是“先行發生”。如果一個操作“先行發生”,這個操作也不代表是“時間上的先發生”的,因為存在指令重排的可能性。時間先后順序與先行發生原則之間基本沒有因果關系,所以我們衡量并發安全問題的時候不要受時間順序的干擾,一切必須以先行發生原則為準

參考《深入理解Java虛擬機第三版周志明》

到此這篇關于Java并發之原子性 有序性 可見性及Happen Before原則的文章就介紹到這了,更多相關Java 并發原則內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!

原文鏈接:https://blog.csdn.net/u012988901/article/details/111936894

延伸 · 閱讀

精彩推薦
  • Java教程xml與Java對象的轉換詳解

    xml與Java對象的轉換詳解

    這篇文章主要介紹了xml與Java對象的轉換詳解的相關資料,需要的朋友可以參考下...

    Java教程網2942020-09-17
  • Java教程Java實現搶紅包功能

    Java實現搶紅包功能

    這篇文章主要為大家詳細介紹了Java實現搶紅包功能,采用多線程模擬多人同時搶紅包,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙...

    littleschemer13532021-05-16
  • Java教程20個非常實用的Java程序代碼片段

    20個非常實用的Java程序代碼片段

    這篇文章主要為大家分享了20個非常實用的Java程序片段,對java開發項目有所幫助,感興趣的小伙伴們可以參考一下 ...

    lijiao5352020-04-06
  • Java教程小米推送Java代碼

    小米推送Java代碼

    今天小編就為大家分享一篇關于小米推送Java代碼,小編覺得內容挺不錯的,現在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧...

    富貴穩中求8032021-07-12
  • Java教程Java8中Stream使用的一個注意事項

    Java8中Stream使用的一個注意事項

    最近在工作中發現了對于集合操作轉換的神器,java8新特性 stream,但在使用中遇到了一個非常重要的注意點,所以這篇文章主要給大家介紹了關于Java8中S...

    阿杜7482021-02-04
  • Java教程升級IDEA后Lombok不能使用的解決方法

    升級IDEA后Lombok不能使用的解決方法

    最近看到提示IDEA提示升級,尋思已經有好久沒有升過級了。升級完畢重啟之后,突然發現好多錯誤,本文就來介紹一下如何解決,感興趣的可以了解一下...

    程序猿DD9332021-10-08
  • Java教程Java使用SAX解析xml的示例

    Java使用SAX解析xml的示例

    這篇文章主要介紹了Java使用SAX解析xml的示例,幫助大家更好的理解和學習使用Java,感興趣的朋友可以了解下...

    大行者10067412021-08-30
  • Java教程Java BufferWriter寫文件寫不進去或缺失數據的解決

    Java BufferWriter寫文件寫不進去或缺失數據的解決

    這篇文章主要介紹了Java BufferWriter寫文件寫不進去或缺失數據的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望...

    spcoder14552021-10-18
主站蜘蛛池模板: 天天操免费视频 | 奇米色88欧美一区二区 | 久久久久久久久女黄 | 丝袜捆绑调教视频免费区 | 51精品 | 黑帮大佬与我的365天2标清中文 | 91久久国产成人免费观看资源 | 99国产精品免费观看视频 | 69av导航| 97热久久免费频精品99国产成人 | 国产精品久久久久aaaa | 国产亚洲精品aaa大片 | 国产精品福利短视在线播放频 | 国产精品福利短视在线播放频 | 亚洲免费闲人蜜桃 | 免费大秀视频在线播放 | 皇上好大好硬好涨好深好爽 | 欧美色图日韩 | 青青草99久久精品国产综合 | 色老汉 | 亚洲 综合 自拍 精品 在线 | 国产精品 色 | 欧美日韩专区国产精品 | 调教肉文 | 亚州人成网在线播放 | 国产视频一区 | 校花小雪灌满了男人们的浓浆 | 日本视频在线观看 | 国产精品久久免费观看 | 精品一区二区三区在线成人 | 亚洲国产精品成人久久 | 99这里精品 | 五月香婷 | 欧美一级视频在线高清观看 | 欧美视频一区二区三区四区 | 亚洲午夜性春猛交xxxx | 日产精品一卡2卡三卡4乱码久久 | 5g影院天天爽 | 妹妹你插的我好爽 | 男女xxoo做爰猛烈动态一 | 精品久久成人 |