并發(fā)編程-happens-before

      網(wǎng)友投稿 603 2022-05-29

      文章目錄

      概述

      happens-before定義

      happens-before規(guī)則

      7個原則

      volatile變量規(guī)則

      start()規(guī)則

      join()規(guī)則

      happens-before與JMM的關(guān)系

      JMM的設(shè)計

      概述

      happens-before是JMM最核心的概念,理解happens-before是理解JMM的關(guān)鍵

      從JDK 5開始,Java使用新的JSR-133內(nèi)存模型。

      JSR-133使用happens-before的概念來闡述操作之間的內(nèi)存可見性。

      在JMM中,如果一個操作執(zhí)行的結(jié)果需要對另一個操作可見,那么這兩個操作之間必須要存在happens-before關(guān)系。

      這里提到的兩個操作既可以是在一個線程之內(nèi),也可以是在不同線程之間。

      happens-before定義

      JSR-133使用happens-before的概念來指定兩個操作之間的執(zhí)行順序。由于這兩個操作可以在一個線程之內(nèi),也可以是在不同線程之間。因此,JMM可以通過happens-before關(guān)系向開發(fā)人員提供跨線程的內(nèi)存可見性保證(如果A線程的寫操作a與B線程的讀操作b之間存在happens-before關(guān)系,盡管a操作和b操作在不同的線程中執(zhí)行,但JMM向程序員保證a操作將對b操作可見)。

      happens-before規(guī)則

      7個原則

      程序順序規(guī)則:一個線程中的每個操作,happens-before于該線程中的任意后續(xù)操作

      監(jiān)視器鎖規(guī)則:對一個鎖的解鎖,happens-before于隨后對這個鎖的加鎖。

      volatile變量規(guī)則:對一個volatile域的寫,happens-before于任意后續(xù)對這個volatile域的讀。

      傳遞性:如果A happens-before B,且B happens-before C,那么A happens-before C

      start()規(guī)則:如果線程A執(zhí)行操作ThreadB.start()(啟動線程B),那么A線程的ThreadB.start()操作happens-before于線程B中的任意操作。

      join()規(guī)則:如果線程A執(zhí)行操作ThreadB.join()并成功返回,那么線程B中的任意操作happens-before于線程A從ThreadB.join()操作成功返回。

      volatile變量規(guī)則

      volatile寫-讀建立的happens-before關(guān)系圖如下

      ·1 happens-before 2和3 happens-before 4由程序順序規(guī)則產(chǎn)生。由于編譯器和處理器都要遵守as-if-serial語義,也就是說,as-if-serial語義保證了程序順序規(guī)則。因此,可以把程序順序規(guī)則看成是對as-if-serial語義的“封裝”。

      2 happens-before 3是由volatile規(guī)則產(chǎn)生。前面提到過,對一個volatile變量的讀,總是能看到(任意線程)之前對這個volatile變量最后的寫入。因此,volatile的這個特性可以保證實現(xiàn)volatile規(guī)則。

      ·1 happens-before 4是由傳遞性規(guī)則產(chǎn)生的。這里的傳遞性是由volatile的內(nèi)存屏障插入策略和volatile的編譯器重排序規(guī)則共同來保證的。

      start()規(guī)則

      假設(shè)線程A在執(zhí)行的過程中,通過執(zhí)行ThreadB.start()來啟動線程B;同時,假設(shè)線程A在執(zhí)行ThreadB.start()之前修改了一些共享變量,線程B在開始執(zhí)行后會讀這些共享變量。下圖是該程序?qū)?yīng)的happens-before關(guān)系圖。

      1 happens-before 2由程序順序規(guī)則產(chǎn)生。2 happens-before 4由start()規(guī)則產(chǎn)生。根據(jù)傳遞性,將有1 happens-before 4。這實意味著,線程A在執(zhí)行ThreadB.start()之前對共享變量所做的修改,接下來在線程B開始執(zhí)行后都將確保對線程B可見。

      join()規(guī)則

      假設(shè)線程A在執(zhí)行的過程中,通過執(zhí)行ThreadB.join()來等待線程B終止;同時,假設(shè)線程B在終止之前修改了一些共享變量,線程A從ThreadB.join()返回后會讀這些共享變量。 該程序?qū)?yīng)的happens-before關(guān)系圖如下:

      2 happens-before 4由join()規(guī)則產(chǎn)生;4 happens-before 5由程序順序規(guī)則產(chǎn)生。根據(jù)傳遞性規(guī)則,將有2 happens-before 5。這意味著,線程A執(zhí)行操作ThreadB.join()并成功返回后,線程B中的任意操作都將對線程A可見。

      兩個操作之間具有happens-before關(guān)系,并不意味著前一個操作必須要在后一個操作之前執(zhí)行!happens-before僅僅要求前一個操作(執(zhí)行的結(jié)果)對后一個操作可見,且前一個操作按順序排在第二個操作之前(the first is visible to and ordered before the second)

      happens-before與JMM的關(guān)系

      如上圖所示,一個 happens-before 規(guī)則通常對應(yīng)于多個編譯器重排序規(guī)則和處理器重排序規(guī)則。對于開發(fā)人員來說,happens-before 規(guī)則簡單易懂,它避免程序員為了理解 JMM 提供的內(nèi)存可見性保證而去學(xué)習(xí)復(fù)雜的重排序規(guī)則以及這些規(guī)則的具體實現(xiàn)

      JMM的設(shè)計

      從JMM設(shè)計者的角度,在設(shè)計JMM時,需要考慮兩個關(guān)鍵因素

      開發(fā)人員對內(nèi)存模型的使用。程序員希望內(nèi)存模型易于理解、易于編程。

      開發(fā)人員希望基于一個強內(nèi)存模型來編寫代碼。

      編譯器和處理器對內(nèi)存模型的實現(xiàn)。編譯器和處理器希望內(nèi)存模型對它們的束縛越少越好,這樣它們就可以做盡可能多的優(yōu)化來提高性能。

      編譯器和處理器希望實現(xiàn)一個弱內(nèi)存模型。

      由于這兩個因素互相矛盾,所以JSR-133設(shè)計JMM時的核心目標(biāo)就是找到一個好的

      平衡點:一方面,要為程序員提供足夠強的內(nèi)存可見性保證;另一方面,對編譯器和處理器的限制要盡可能地放松 。

      舉個例子來看JSR-133是如何實現(xiàn)這一目標(biāo)的

      double pi = 3.14;  // A double r = 1.0;    // B double area = pi * r * r; // C

      1

      2

      3

      上面計算圓的面積的示例代碼存在3個happens-before關(guān)系,如下。

      ·A happens-before B。 ·B happens-before C。 ·A happens-before C。

      1

      2

      3

      高并發(fā)編程-happens-before

      在3個happens-before關(guān)系中,2和3是必需的,但1是不必要的。因此,JMM把happens-before要求禁止的重排序分為了下面兩類

      ·

      會改變程序執(zhí)行結(jié)果的重排序。

      不會改變程序執(zhí)行結(jié)果的重排序。

      JMM對這兩種不同性質(zhì)的重排序,采取了不同的策略,如下

      對于會改變程序執(zhí)行結(jié)果的重排序,JMM要求編譯器和處理器必須禁止這種重排序

      對于不會改變程序執(zhí)行結(jié)果的重排序,JMM對編譯器和處理器不做要求(JMM允許這種重排序)。

      從上圖可以看出兩點,如下

      JMM向程序員提供的happens-before規(guī)則能滿足程序員的需求。

      JMM的happens-before規(guī)則不但簡單易懂,而且也向開發(fā)人員提供了足夠強的內(nèi)存可見性保證(有些內(nèi)存可見性保證其并不一定真實存在,比如上面的A happens-before B)

      ·JMM對編譯器和處理器的束縛已經(jīng)盡可能少。從上面的分析可以看出,JMM其實是在遵循一個基本原則:

      只要不改變程序的執(zhí)行結(jié)果(指的是單線程程序和正確同步的多線程程序)編譯器和處理器怎么優(yōu)化都行。

      Java 任務(wù)調(diào)度

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。

      上一篇:sysbench壓測mysql性能調(diào)優(yōu)案例分享
      下一篇:基礎(chǔ)備忘:C++類靜態(tài)成員與類靜態(tài)成員函數(shù)詳解
      相關(guān)文章
      国产成人高清亚洲| 亚洲一区二区三区在线播放| 亚洲午夜爱爱香蕉片| 日韩欧美亚洲国产精品字幕久久久| 亚洲jizzjizz在线播放久| 亚洲美女视频免费| 亚洲一级二级三级不卡| 亚洲视频2020| 国产亚洲成av片在线观看| 亚洲色大成网站www永久一区| 亚洲精品久久久久无码AV片软件| 亚洲中文字幕久久精品无码2021| 亚洲日本视频在线观看| 亚洲成人免费在线观看| 亚洲一区二区三区久久| 亚洲黄色在线观看网站| 亚洲理论片在线观看| 亚洲国产一区在线观看| 亚洲中文无码a∨在线观看| 亚洲大片免费观看| 精品亚洲成A人无码成A在线观看| 亚洲男人天堂2018av| 亚洲精品国产国语| 亚洲av无码片vr一区二区三区| 色窝窝亚洲av网| 亚洲av无码兔费综合| 日韩色视频一区二区三区亚洲| 国产成人人综合亚洲欧美丁香花| 九月婷婷亚洲综合在线| 亚洲精品成人片在线观看| 国产亚洲无线码一区二区| 亚洲AV福利天堂一区二区三| 亚洲αv久久久噜噜噜噜噜| 久久久亚洲裙底偷窥综合| 亚洲国产精品久久久久秋霞影院 | 亚洲国产成人精品久久| 亚洲人配人种jizz| 国产亚洲一卡2卡3卡4卡新区| 亚洲乱码国产一区网址| 亚洲色精品vr一区二区三区| 婷婷久久久亚洲欧洲日产国码AV |