欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java并發(fā)之原子性 有序性 可見(jiàn)性及Happen Before原則

 更新時(shí)間:2021年09月24日 08:48:14   作者:沒(méi)頭腦遇到不高興  
一提到happens-before原則,就讓人有點(diǎn)“丈二和尚摸不著頭腦”。這個(gè)涵蓋了整個(gè)JMM中可見(jiàn)性原則的規(guī)則,究竟如何理解,把我個(gè)人一些理解記錄下來(lái)。下面可以和小編一起學(xué)習(xí)Java 并發(fā)四個(gè)原則

1.原子性(Atomicity)

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

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

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

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

2.可見(jiàn)性(Visibility)

可見(jiàn)性就是指當(dāng)一個(gè)線程修改了共享變量的值時(shí),其他線程能夠立即得知這個(gè)修改。上文在講解volatile變量的時(shí)候我們已詳細(xì)討論過(guò)這一點(diǎn)。Java內(nèi)存模型是通過(guò)在變量修改后將新值同步回主內(nèi)存,在變量讀取前從主內(nèi)存刷新變量值這種依賴主內(nèi)存作為傳遞媒介的方式來(lái)實(shí)現(xiàn)可見(jiàn)性的,無(wú)論是普通變量還是volatile變量都是如此。普通變量與volatile變量的區(qū)別是,volatile的特殊規(guī)則保證了新值能立即同步到主內(nèi)存,以及每次使用前立即從主內(nèi)存刷新。因此我們可以說(shuō)volatile保證了多線程操作時(shí)變量的可見(jiàn)性,而普通變量則不能保證這一點(diǎn)。

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

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

public static final int i;
public final int j;
static {
	i = 0;
	// 省略后續(xù)動(dòng)作
}
{
	// 也可以選擇在構(gòu)造函數(shù)中初始化
	j = 0;
	// 省略后續(xù)動(dòng)作
}

3.有序性(Ordering)

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

volatile用來(lái)保證可見(jiàn)性和有序性,synchronized則對(duì)三種特性都可以保證。

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

只靠sychronized和volatile關(guān)鍵字來(lái)保證原子性、可見(jiàn)性以及有序性,那么編寫并發(fā)程序可能會(huì)顯得十分麻煩,幸運(yùn)的是,從JDK 5開始,Java使用新的JSR-133內(nèi)存模型,提供了
happens-before 原則來(lái)輔助保證程序執(zhí)行的原子性、可見(jiàn)性以及有序性的問(wèn)題,它是判斷數(shù)據(jù)是否存在競(jìng)爭(zhēng)、線程是否安全的依據(jù)。

先行發(fā)生是Java內(nèi)存模型中定義的兩項(xiàng)操作之間的偏序關(guān)系,比如說(shuō)操作A先行發(fā)生于操作B,其實(shí)就是說(shuō)在發(fā)生操作B之前,操作A產(chǎn)生的影響能被操作B觀察到,“影響”包括修改了內(nèi)存中共享變量的值、發(fā)送了消息、調(diào)用了方法等。下面三個(gè)偽代碼:

// 以下操作在線程A中執(zhí)行
i = 1;
// 以下操作在線程B中執(zhí)行
j = i;
// 以下操作在線程C中執(zhí)行
i = 2;

假設(shè)線程A中的操作“i=1”先行發(fā)生于線程B的操作“j=i”,那我們就可以確定在線程B的操作執(zhí)行后,變量j的值一定是等于1,得出這個(gè)結(jié)論的依據(jù)有兩個(gè):一是根據(jù)先行發(fā)生原則,“i=1”的結(jié)果可以被觀察到;二是線程C還沒(méi)登場(chǎng),線程A操作結(jié)束之后沒(méi)有其他線程會(huì)修改變量i的值?,F(xiàn)在再來(lái)考慮線程C,我們依然保持線程A和B之間的先行發(fā)生關(guān)系,而C出現(xiàn)在線程A和B的操作之間,但是C與B沒(méi)有先行發(fā)生關(guān)系,那j的值會(huì)是多少呢?答案是不確定!1和2都有可能,因?yàn)榫€程C對(duì)變量i的影響可能會(huì)被線程B觀察到,也可能不會(huì),這時(shí)候線程B就存在讀取到過(guò)期數(shù)據(jù)的風(fēng)險(xiǎn),不具備多線程安全性。

下面是Java內(nèi)存模型下一些“天然的”先行發(fā)生關(guān)系,這些先行發(fā)生關(guān)系無(wú)須任何同步器協(xié)助就已經(jīng)存在,可以在編碼中直接使用。如果兩個(gè)操作之間的關(guān)系不在此列,并且無(wú)法從下列規(guī)則推導(dǎo)出來(lái),則它們就沒(méi)有順序性保障,虛擬機(jī)可以對(duì)它們隨意地進(jìn)行重排序。

  • 程序次序規(guī)則(Program Order Rule):在一個(gè)線程內(nèi),按照控制流順序,書寫在前面的操作先行發(fā)生于書寫在后面的操作。注意,這里說(shuō)的是控制流順序而不是程序代碼順序,因?yàn)橐紤]分支、循環(huán)等結(jié)構(gòu)。
  • 管程鎖定規(guī)則(Monitor Lock Rule):一個(gè)unlock操作先行發(fā)生于后面對(duì)同一個(gè)鎖的lock操作。這里必須強(qiáng)調(diào)的是“同一個(gè)鎖”,而“后面”是指時(shí)間上的先后。
  • volatile變量規(guī)則(Volatile Variable Rule):對(duì)一個(gè)volatile變量的寫操作先行發(fā)生于后面對(duì)這個(gè)變量的讀操作,這里的“后面”同樣是指時(shí)間上的先后。
  • 線程啟動(dòng)規(guī)則(Thread Start Rule):Thread對(duì)象的start()方法先行發(fā)生于此線程的每一個(gè)動(dòng)作。
  • 線程終止規(guī)則(Thread Termination Rule):線程中的所有操作都先行發(fā)生于對(duì)此線程的終止檢測(cè),我們可以通過(guò)Thread::join()方法是否結(jié)束、Thread::isAlive()的返回值等手段檢測(cè)線程是否已經(jīng)終止執(zhí)行。
  • 線程中斷規(guī)則(Thread Interruption Rule):對(duì)線程interrupt()方法的調(diào)用先行發(fā)生于被中斷線程的代碼檢測(cè)到中斷事件的發(fā)生,可以通過(guò)Thread::interrupted()方法檢測(cè)到是否有中斷發(fā)生。
  • 對(duì)象終結(jié)規(guī)則(Finalizer Rule):一個(gè)對(duì)象的初始化完成(構(gòu)造函數(shù)執(zhí)行結(jié)束)先行發(fā)生于它的finalize()方法的開始。
  • 傳遞性(Transitivity):如果操作A先行發(fā)生于操作B,操作B先行發(fā)生于操作C,那就可以得出操作A先行發(fā)生于操作C的結(jié)論。

一個(gè)操作“時(shí)間上的先發(fā)生”不代表這個(gè)操作會(huì)是“先行發(fā)生”。如果一個(gè)操作“先行發(fā)生”,這個(gè)操作也不代表是“時(shí)間上的先發(fā)生”的,因?yàn)榇嬖谥噶钪嘏诺目赡苄?。時(shí)間先后順序與先行發(fā)生原則之間基本沒(méi)有因果關(guān)系,所以我們衡量并發(fā)安全問(wèn)題的時(shí)候不要受時(shí)間順序的干擾,一切必須以先行發(fā)生原則為準(zhǔn)

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

到此這篇關(guān)于Java并發(fā)之原子性 有序性 可見(jiàn)性及Happen Before原則的文章就介紹到這了,更多相關(guān)Java 并發(fā)原則內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 一文搞懂hashCode()和equals()方法的原理

    一文搞懂hashCode()和equals()方法的原理

    這篇文章主要介紹了詳解hashCode()和equals()的本質(zhì)區(qū)別和聯(lián)系,本文先對(duì)兩種方法作了介紹,然后對(duì)二者聯(lián)系進(jìn)行分析,具有一定參考價(jià)值,需要的朋友可以了解下
    2020-06-06
  • 深入了解Spring中的依賴注入DI

    深入了解Spring中的依賴注入DI

    這篇文章主要介紹了Spring?中的依賴注入,包括注入的方式,寫法,該選擇哪個(gè)注入方式以及可能出現(xiàn)的循環(huán)依賴問(wèn)題等內(nèi)容,需要的可以參考一下
    2023-06-06
  • Linux下Java開發(fā)環(huán)境搭建以及第一個(gè)HelloWorld

    Linux下Java開發(fā)環(huán)境搭建以及第一個(gè)HelloWorld

    這篇文章主要介紹了Linux下Java開發(fā)環(huán)境搭建以及第一個(gè)HelloWorld的實(shí)現(xiàn)過(guò)程,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2015-09-09
  • SpringBoot權(quán)限認(rèn)證-Sa-Token的使用詳解

    SpringBoot權(quán)限認(rèn)證-Sa-Token的使用詳解

    Sa-Token是一款輕量級(jí)Java權(quán)限認(rèn)證框架,它簡(jiǎn)化了權(quán)限管理,提高了開發(fā)效率,本文通過(guò)實(shí)例介紹了Sa-Token的基本概念、與其他框架的比較、基本語(yǔ)法和高級(jí)用法,并探討了其核心原理和實(shí)際應(yīng)用場(chǎng)景,感興趣的朋友一起看看吧
    2024-09-09
  • 微服務(wù)Spring?Cloud?Alibaba?的介紹及主要功能詳解

    微服務(wù)Spring?Cloud?Alibaba?的介紹及主要功能詳解

    Spring?Cloud?是一個(gè)通用的微服務(wù)框架,適合于多種環(huán)境下的開發(fā),而?Spring?Cloud?Alibaba?則是為阿里巴巴技術(shù)棧量身定制的解決方案,本文給大家介紹Spring?Cloud?Alibaba?的介紹及主要功能,感興趣的朋友跟隨小編一起看看吧
    2024-08-08
  • java分形繪制科赫雪花曲線(科赫曲線)代碼分享

    java分形繪制科赫雪花曲線(科赫曲線)代碼分享

    部分與整體以某種形式相似的形,稱為分形,科赫曲線是一種外形像雪花的幾何曲線,所以又稱為雪花曲線,它是分形曲線中的一種,畫法如下
    2013-12-12
  • SpringBootTest測(cè)試時(shí)不啟動(dòng)程序的問(wèn)題

    SpringBootTest測(cè)試時(shí)不啟動(dòng)程序的問(wèn)題

    這篇文章主要介紹了SpringBootTest測(cè)試時(shí)不啟動(dòng)程序的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • Mybatis-Plus批量添加或修改數(shù)據(jù)的3種方式總結(jié)

    Mybatis-Plus批量添加或修改數(shù)據(jù)的3種方式總結(jié)

    使用Mybatis-plus可以很方便的實(shí)現(xiàn)批量新增和批量修改,不僅比自己寫foreach遍歷方便很多,而且性能也更加優(yōu)秀,下面這篇文章主要給大家介紹了關(guān)于Mybatis-Plus批量添加或修改數(shù)據(jù)的3種方式,需要的朋友可以參考下
    2023-05-05
  • Java Web 登錄頁(yè)面的實(shí)現(xiàn)代碼實(shí)例

    Java Web 登錄頁(yè)面的實(shí)現(xiàn)代碼實(shí)例

    這篇文章主要介紹了Java Web 登錄頁(yè)面的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • SpringCloud之熔斷器Hystrix的實(shí)現(xiàn)

    SpringCloud之熔斷器Hystrix的實(shí)現(xiàn)

    這篇文章主要介紹了SpringCloud之熔斷器Hystrix的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08

最新評(píng)論