多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國(guó)內(nèi)最全I(xiàn)T社區(qū)平臺(tái) 聯(lián)系我們 | 收藏本站
阿里云優(yōu)惠2
您當(dāng)前位置:首頁(yè) > php開源 > php教程 > Java并發(fā)編程的藝術(shù)(三)——volatile

Java并發(fā)編程的藝術(shù)(三)——volatile

來源:程序員人生   發(fā)布時(shí)間:2018-06-11 17:09:13 閱讀次數(shù):6620次

1. 并發(fā)編程的兩個(gè)關(guān)鍵問題

并發(fā)是讓多個(gè)線程同時(shí)履行,若線程之間是獨(dú)立的,那并發(fā)實(shí)現(xiàn)起來很簡(jiǎn)單,各自履行各自的就行;但常常多條線程之間需要同享數(shù)據(jù),此時(shí)在并發(fā)編程進(jìn)程中就不可避免要斟酌兩個(gè)問題:通訊 與 同步。

  • 通訊
    通訊是指消息在兩條線程之間傳遞。
    既然要傳遞消息,那接收線程 和 發(fā)送線程之間必須要有個(gè)前后關(guān)系,此時(shí)就需要用到同步。通訊和同步是相輔相成的。

  • 同步
    同步是指,控制多條線程之間的履行次序。

2. 通訊的方式

2.1 通訊方式的種類

線程之間的通訊1共有兩種方式:同享內(nèi)存 和 消息傳遞。

  • 同享內(nèi)存
    同享內(nèi)存指的是多條線程同享同1片內(nèi)存,發(fā)送者將消息寫入內(nèi)存,接收者從內(nèi)存中讀取消息,從而實(shí)現(xiàn)了消息的傳遞。
    但這類方式有個(gè)弊端,即需要程序員來控制線程的同步,即線程的履行次序。

這類方式并沒有真正地實(shí)現(xiàn)消息傳遞,只是從結(jié)果上來看就像是將消息從1條線程傳遞到了另外一條線程。

  • 消息傳遞
    顧名思義,消息傳遞指的是發(fā)送線程直接將消息傳遞給接收線程。
    由于履行次序由并發(fā)機(jī)制完成,因此不需要程序員添加額外的同步機(jī)制,但需要聲明消息發(fā)送和接收的代碼。

綜上所述:對(duì)同享內(nèi)存的通訊方式,需要進(jìn)行顯示的同步,隱式的通訊;
而對(duì)消息傳遞的通訊方式,需要隱式的同步,顯示的通訊。

2.2 Java使用的通訊方式

Java使用同享內(nèi)存的方式實(shí)現(xiàn)多線程之間的消息傳遞。因此,程序員需要寫額外的代碼用于線程之間的同步。

PS:其實(shí)同享內(nèi)存的方式從實(shí)現(xiàn)進(jìn)程來看,跟消息傳遞1點(diǎn)關(guān)系都沒有:1條線程將消息存入同享內(nèi)存,另外一條線程從同享內(nèi)存中讀這條消息。
但從結(jié)果來看,全部進(jìn)程就好像是1條消息被從線程A傳遞到了線程B。
這類方式之所以能實(shí)現(xiàn)消息傳遞,依托于兩點(diǎn):

  • 必須有1片同享的內(nèi)存
  • 必須要實(shí)現(xiàn)多線程的同步

3. Java多線程的內(nèi)存模型(簡(jiǎn)化版)

所有線程都同享1片內(nèi)存,用于存儲(chǔ)同享變量;
另外,每條線程都有各自的存儲(chǔ)空間,存儲(chǔ)各自的局部變量、方法參數(shù)、異常對(duì)象。

4. volatile是甚么?

Java采取同享內(nèi)存的方式實(shí)現(xiàn)消息傳遞,而同享內(nèi)存需要依托于同步。Java提供了synchronized、volatile關(guān)鍵字實(shí)現(xiàn)同步。另外volatile關(guān)鍵字還具有1些額外的功能。

5. volatile的使用

在成員變量前加上該關(guān)鍵字便可。

public volatile boolean flag;

6. volatile的特性

6.1 重排序

重排序是計(jì)算機(jī)為了提高程序履行效力而對(duì)代碼的履行順序進(jìn)行調(diào)劑。你以為代碼是1行行順序履行的,但實(shí)際并不是如此,重排序詳解請(qǐng)移步至:Java并發(fā)編程的藝術(shù)(2)——重排序

若兩行指令之間沒有依賴關(guān)系,那末計(jì)算機(jī)可以對(duì)他們的順序進(jìn)行重排序,但如果兩行之間的某個(gè)變量被volatile修飾后,重排序規(guī)則會(huì)產(chǎn)生變化。

在以下情況下,即便兩行代碼之間沒有依賴關(guān)系,也不會(huì)產(chǎn)生重排序:

  • volatile讀

    • 若volatile讀操作的前1行動(dòng)volatile讀/寫,則這兩行不會(huì)產(chǎn)生重排序
    • volatile讀操作和它后1行代碼都不會(huì)產(chǎn)生重排序
  • volatile寫

    • volatile寫操作和它前1行代碼都不會(huì)產(chǎn)生重排序;
    • 若volatile寫操作的后1行代碼為volatile讀/寫,則這兩行不會(huì)產(chǎn)生重排序。

6.2 可見性

甚么是內(nèi)存可見性?

“內(nèi)存可見性”指的是1條線程修改完1個(gè)同享變量后,另外一個(gè)線程若訪問這個(gè)變量將會(huì)訪問到修改后的值。即:1條線程對(duì)同享變量的修改,對(duì)其他線程立便可見。

但如果未對(duì)同享變量采取同步機(jī)制,那末同享變量的修改不會(huì)對(duì)其他線程立便可見。

為何會(huì)出現(xiàn)內(nèi)存不可見的情況?

通過上文可知,在Java中每條線程都有各自獨(dú)立的存儲(chǔ)空間,另外還有1個(gè)所有線程同享的內(nèi)存空間。
當(dāng)開啟線程時(shí),系統(tǒng)會(huì)將同享內(nèi)存中的所有同享變量拷貝1份到線程專屬的存儲(chǔ)空間中。接下來該線程在結(jié)束前的所有操作都是基于自己的存儲(chǔ)空間進(jìn)行的。因此,若1條線程改變了1個(gè)同享變量,僅僅改變的是這條線程專屬存儲(chǔ)空間中的變量值;此時(shí)若其他線程訪問這個(gè)變量,訪問的依然是先前從同享存儲(chǔ)空間讀出來的值。
但是我們希望1條線程將某個(gè)同享變量修改后,其他線程能立即訪問到這個(gè)最新的值,而不是失效值。
這時(shí)候就需要同步機(jī)制來解決這個(gè)問題。

如何確保同享變量的可見性?

要確保所有同享變量對(duì)所有線程是可見的,就需要給所有同享變量使用同步。在Java中你可以選擇將同享變量用同步代碼塊包裹或用volatile修飾同享變量。

為何volatile能保證同享變量的內(nèi)存可見性?

volatile修飾了1個(gè)成員變量后,這個(gè)變量的讀寫就會(huì)比普通變量多1些步驟。

  • volatile變量寫
    當(dāng)被volatile修飾的變量進(jìn)行寫操作時(shí),這個(gè)變量將會(huì)被直接寫入同享內(nèi)存,而非線程的專屬存儲(chǔ)空間。

  • volatile變量讀
    當(dāng)讀取1個(gè)被volatile修飾的變量時(shí),會(huì)直接從同享內(nèi)存中讀,而非線程專屬的存儲(chǔ)空間中讀。

通過對(duì)volatile變量讀寫的限制,就可以保證線程每次讀到的都是最新的值,從而確保了該變量的內(nèi)存可見性。

volatile變量贈(zèng)送的附加功能

進(jìn)行volatile寫操作時(shí),不但會(huì)將volatile變量寫入同享內(nèi)存,系統(tǒng)還會(huì)將當(dāng)前線程專屬空間中的所有同享變量寫入同享內(nèi)存。
進(jìn)行volatile讀操作時(shí),系統(tǒng)也會(huì)1次性將同享內(nèi)存中所有同享變量讀入線程專屬空間。
這就意味著,如果普通變量在volatile寫操作之前被修改,那末在volatile讀操作以后就可以正確讀到他們。
但是,在volatile寫操作以后被修改的普通變量 和 在volatile讀操作之前被訪問的普通變量 都不具有內(nèi)存可見性。

6.3 原子性

甚么是原子性?

原子性指的是1組操作必須1起完成,中途不能被中斷。

volatile能確保long、double讀寫的原子性

在Java中的所有類型中,有l(wèi)ong、double類型比較特殊,他們占據(jù)8字節(jié)(64比特),其余類型都小于64比特。在32位操作系統(tǒng)中,CPU1次只能讀取/寫入32位的數(shù)據(jù),因此對(duì)64位的long、double變量的讀寫會(huì)進(jìn)行兩步。在多線程中,若1條線程只寫入了long型變量的前32位,緊接著另外一條線程讀取了這個(gè)只有“1半”的變量,從而就讀到了1個(gè)毛病的數(shù)據(jù)。
為了不這類情況,需要在用volatile修飾long、double型變量。

在內(nèi)存可見性與原子性上,volatile就相當(dāng)因而同步的setter和getter函數(shù)。但其實(shí)不具有volatile的重排序規(guī)則,同步塊只確保同步塊內(nèi)部的指令不產(chǎn)生重排序,其實(shí)不確保同步塊之外的指令的重排序。

PS1:Java中的byte居然是字節(jié),bit才是比特(位)。
PS2:char和short⑵字節(jié)、int和float⑷字節(jié)、long和double⑻字節(jié)、byte⑴字節(jié)

QA:在同步塊中調(diào)用wait函數(shù)是不是會(huì)破壞原子性?

生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對(duì)您的學(xué)習(xí)有所幫助,可以手機(jī)掃描二維碼進(jìn)行捐贈(zèng)
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關(guān)閉
程序員人生
主站蜘蛛池模板: 99re这里有免费视频精品 | h肉在线| 德国艳星videos极品 | 国产欧美日韩免费一区二区 | 久久精品免看国产成 | h视频在线观看免费网站 | 午夜秋霞成人理论 | 香蕉福利视频 | 免费看毛片网站 | 五月天久久综合 | 中文字幕成人 | 欧美日韩亚洲一区二区三区 | 一二三四日本手机高清视频 | 在线免费观看成年人视频 | www.日本com| 性做久久| 久久欧美精品欧美九久欧美 | 国产在线a| 在线观看成年人免费视频 | 在线视频中文 | 中文字幕一区二区三区永久 | 成年人的天堂 | 99re66热这里只有精品17 | 亚洲一级在线 | 日本一级级特黄特色大片 | 日韩欧美一二三区 | 校园春色偷拍自拍 | 免费xxxxx在线观看网站 | 色综合久久综合欧美综合网 | 91se在线看片国产免费观看 | 成人99国产精品一级毛片 | 中文字幕一区二区三区有限公司 | h视频网站在线观看 | 日本高清护士xxxxx | 国产 | 久而欧洲野花视频欧洲1 | 亚洲色图第三页 | 免费一级做a爰片久久毛片潮喷 | www日本www| 涩涩免费播放观看在线视频 | 日韩久久精品 | 亚洲已满18点击进入在线观看 |