成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久

您的位置:首頁技術文章
文章詳情頁

Java關鍵字volatile知識點總結

瀏覽:73日期:2022-08-18 11:23:08
volatile是什么

volatile關鍵字是Java提供的一種輕量級同步機制。它能夠保證可見性和有序性,但是不能保證原子性

可見性

對于volatile的可見性,先看看這段代碼的執行

Java關鍵字volatile知識點總結

flag默認為true 創建一個線程A去判斷flag是否為true,如果為true循環執行i++操作兩秒后,創建另一個線程B將flag修改為false 線程A沒有感知到flag已經被修改成false了,不能跳出循環

這相當于啥呢?相當于你的女神和你說,你好好努力,年薪百萬了就嫁給你,你聽了之后,努力賺錢。3年之后,你年薪百萬了,回去找你女神,結果發現你女神結婚了,她結婚的消息根本沒有告訴你!難不難受?

女神結婚可以不告訴你,可是Java代碼中的屬性都是存在內存中,一個線程的修改為什么另一個線程為什么不可見呢?這就不得不提到Java中的內存模型了,Java中的內存模型,簡稱JMM,JMM定義了線程和主內存之間的抽象關系,定義了線程之間的共享變量存儲在主內存中,每個線程都有一個私有的本地內存,本地內存中存儲了該線程以讀/寫共享變量的副本,它涵蓋了緩存、寫緩沖區、寄存器以及其他的硬件和編譯器優化。

注意!JMM是一個屏蔽了不同操作系統架構的差異的抽象概念,只是一組Java規范。

Java關鍵字volatile知識點總結

了解了JMM,現在我們再回顧一下文章開頭的那段代碼,為什么線程B修改了flag線程A看到的還是原來的值呢?

Java關鍵字volatile知識點總結

因為線程A復制了一份剛開始的flage=true到本地內存,之后線程A使用的flag都是這個復制到本地內存的flag。線程B修改了flag之后,將flag的值刷新到主內存,此時主內存的flag值變成了false。線程A是不知道線程B修改了flag,一直用的是本地內存的flag = true。

那么,如何才能讓線程A知道flag被修改了呢?或者說怎么讓線程A本地內存中緩存的flag無效,實現線程間可見呢?用volatile修飾flag就可以做到:

Java關鍵字volatile知識點總結

我們可以看到,用volatile修飾flag之后,線程B修改flag之后線程A是能感知到的,說明了volatile保證了線程同步之間的可見性。

重排序

在闡述volatile有序性之前,需要先補充一些關于重排序的知識。

重排序是指編譯器和處理器為了優化程序性能而對指令序列進行重新排序的一種手段。

為什么要有重排序呢?簡單來說,就是為了提升執行效率。為什么能提升執行效率呢?我們看下面這個例子:

Java關鍵字volatile知識點總結

可以看到重排序之后CPU實際執行省略了一個讀取和寫回的操作,也就間接的提升了執行效率。

有一點必須強調的是,上圖的例子只是為了讓讀者更好的理解為什么重排序能提升執行效率,實際上Java里面的重排序并不是基于代碼級別的,從代碼到CPU執行之間還有很多個階段,CPU底層還有一些優化,實際上的執行流程可能并不是上圖的說的那樣。不必過于糾結于此。

重排序可以提高程序的運行效率,但是必須遵循as-if-serial語義。as-if-serial語義是什么呢?簡單來說,就是不管你怎么重排序,你必須保證不管怎么重排序,單線程下程序的執行結果不能被改變。

有序性

上面我們已經介紹了Java有重排序情況,現在我們再來聊一聊volatile的有序性。

先看一個經典的面試題:為什么DDL(double check lock)單例模式需要加volatile關鍵字?

Java關鍵字volatile知識點總結

因為singleton = new Singleton()不是一個原子操作,大概要經過這幾個步驟:

分配一塊內存空間調用構造器,初始化實例 singleton指向分配的內存空間

實際執行的時候,可能發生重排序,導致實際執行步驟是這樣的:

申請一塊內存空間 singleton指向分配的內存空間調用構造器,初始化實例

在singleton指向分配的內存空間之后,singleton就不為空了。但是在沒有調用構造器初始化實例之前,這個對象還處于半初始化狀態,在這個狀態下,實例的屬性都還是默認屬性,這個時候如果有另一個線程調用getSingleton()方法時,會拿到這個半初始化的對象,導致出錯。

而加volatile修飾之后,就會禁止重排序,這樣就能保證在對象初始化完了之后才把singleton指向分配的內存空間,杜絕了一些不可控錯誤的產生。volatile提供了happens-before保證,對volatile變量的寫入happens-before所有其他線程后續對的讀操作。

原理

從上面的DDL單例用例來看,在并發情況下,重排序的存在會導致一些未知的錯誤。而加上volatile之后會防止重排序,那volatile是如何禁止重排序呢?

為了實現volatile的內存語義,JMM會限制特定類型的編譯器和處理器重排序,JMM會針對編譯器制定volatile重排序規則表:

Java關鍵字volatile知識點總結

總結來說就是:

第二個操作是volatile寫,不管第一個操作是什么都不會重排序第一個操作是volatile讀,不管第二個操作是什么都不會重排序第一個操作是volatile寫,第二個操作是volatile讀,也不會發生重排序

如何保證這些操作不會發送重排序呢?就是通過插入內存屏障保證的,JMM層面的內存屏障分為讀(load)屏障和寫(Store)屏障,排列組合就有了四種屏障。對于volatile操作,JMM內存屏障插入策略:

在每個volatile寫操作的前面插入一個StoreStore屏障在每個volatile寫操作的后面插入一個StoreLoad屏障在每個volatile讀操作的后面插入一個LoadLoad屏障在每個volatile讀操作的后面插入一個LoadStore屏障

Java關鍵字volatile知識點總結

上面的屏障都是JMM規范級別的,意思是,按照這個規范寫JDK能保證volatile修飾的內存區域的操作不會發送重排序。

在硬件層面上,也提供了一系列的內存屏障來提供一致性的能力。拿X86平臺來說,主要提供了這幾種內存屏障指令:

lfence指令:在lfence指令前的讀操作當必須在lfence指令后的讀操作前完成,類似于讀屏障 sfence指令:在sfence指令前的寫操作當必須在sfence指令后的寫操作前完成,類似于寫屏障 mfence指令: 在mfence指令前的讀寫操作當必須在mfence指令后的讀寫操作前完成,類似讀寫屏障。

JMM規范需要加這么多內存屏障,但實際情況并不需要加這么多內存屏障。以我們常見的X86處理器為例,X86處理器不會對讀-讀、讀-寫和寫-寫操作做重排序,會省略掉這3種操作類型對應的內存屏障,僅會對寫-讀操作做重排序。所以volatile寫-讀操作只需要在volatile寫后插入StoreLoad屏障。在《The JSR-133 Cookbook for Compiler Writers》中,也很明確的指出了這一點:

Java關鍵字volatile知識點總結

而在x86處理器中,有三種方法可以實現實現StoreLoad屏障的效果,分別為:

mfence指令:上文提到過,能實現全能型屏障,具備lfence和sfence的能力。 cpuid指令:cpuid操作碼是一個面向x86架構的處理器補充指令,它的名稱派生自CPU識別,作用是允許軟件發現處理器的詳細信息。 lock指令前綴:總線鎖。lock前綴只能加在一些特殊的指令前面。

實際上HotSpot關于volatile的實現就是使用的lock指令,只在volatile標記的地方加上帶lock前綴指令操作,并沒有參照JMM規范的屏障設計而使用對應的mfence指令。

加上-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -XcompJVM參數再次執行main方法,在打印的匯編碼中,我們也可以看到有一個lock addl $0x0,(%rsp)的操作。

Java關鍵字volatile知識點總結

在源碼中也可以得到驗證:

Java關鍵字volatile知識點總結

lock addl $0x0,(%rsp)后面的addl $0x0,(%rsp)其實是一個空操作。add是加的意思,0x0是16進制的0,rsp是一種類型寄存器,合起來就是把寄存器的值加0,加0是不是等于什么都沒有做?這段匯編碼僅僅是lock指令的一個載體而已。其實上文也有提到過,lock前綴只能加在一些特殊的指令前面,add就是其中一個指令。

至于Hotspot為什么要使用lock指令而不是mfence指令,按照我的理解,其實就是省事,實現起來簡單。因為lock功能過于強大,不需要有太多的考慮。而且lock指令優先鎖緩存行,在性能上,lock指令也沒有想象中的那么差,mfence指令更沒有想象中的好。所以,使用lock是一個性價比非常高的一個選擇。而且,lock也有對可見性的語義說明。

在《IA-32架構軟件開發人員手冊》的指令表中找到lock:

Java關鍵字volatile知識點總結

我不打算在這里深入闡述lock指令的實現原理和細節,這很容易陷入堆砌技術術語中,而且也超出了本文的范圍,有興趣的可以去看看《IA-32架構軟件開發人員手冊》。

我們只需要知道lock的這幾個作用就可以了:

確保后續指令執行的原子性。在Pentium及之前的處理器中,帶有lock前綴的指令在執行期間會鎖住總線,使得其它處理器暫時無法通過總線訪問內存,很顯然,這個開銷很大。在新的處理器中,Intel使用緩存鎖定來保證指令執行的原子性,緩存鎖定將大大降低lock前綴指令的執行開銷。禁止該指令與前面和后面的讀寫指令重排序。把寫緩沖區的所有數據刷新到內存中。

總結來說,就是lock指令既保證了可見性也保證了原子性。

重要的事情再說一遍,是lock指令既保證了可見性也保證了原子性,和什么緩沖一致性協議啊,MESI什么的沒有一點關系。

為了不讓你把緩存一致性協議和JMM混淆,在前面的文章中,我特意沒有提到過緩存一致性協議,因為這兩者本不是一個維度的東西,存在的意義也不一樣,這一部分,我們下次再聊。

總結

全文重點是圍繞volatile的可見性和有序性展開的,其中花了不少的部分篇幅描述了一些計算機底層的概念,對于讀者來說可能過于無趣,但如果你能認真看完,我相信你或多或少也會有一點收獲。

不去深究,volatile只是一個普通的關鍵字。深入探討,你會發現volatile是一個非常重要的知識點。volatile能將軟件和硬件結合起來,想要徹底弄懂,需要深入到計算機的最底層。但如果你做到了。你對Java的認知一定會有進一步的提升。

只把眼光放在Java語言,似乎顯得非常局限。發散到其他語言,C語言,C++里面也都有volatile關鍵字。我沒有看過C語言,C++里面volatile關鍵字是如何實現的,但我相信底層的原理一定是相通的。

到此這篇關于Java關鍵字volatile知識點總結的文章就介紹到這了,更多相關理解Java關鍵字volatile內容請搜索好吧啦網以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持好吧啦網!

標簽: Java
相關文章:
成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久
国产精品swag| 麻豆精品在线播放| 免费成人在线网站| 国产精品一区视频| 国产精品久久久久四虎| 99免费精品视频| 在线播放中文一区| 久久国产尿小便嘘嘘尿| 玖玖国产精品视频| 午夜久久久久久久久久一区二区| 亚洲国内自拍| 精品少妇一区二区三区在线播放| 经典三级一区二区| 欧美日韩一区三区| 久久99国内精品| 欧美体内she精视频| 日本成人在线不卡视频| 国产精品免费看| 欧美在线观看视频在线| 亚洲欧美国产精品桃花| 中文字幕一区二区三中文字幕| 99国产精品国产精品久久| 日韩视频中午一区| 国产成人午夜高潮毛片| 91麻豆精品国产91久久久久久久久 | 国产午夜精品美女毛片视频| 国产成人综合在线观看| 日韩免费观看高清完整版在线观看| 国产一区在线视频| 欧美一级艳片视频免费观看| 成人性生交大片免费看中文网站| 日韩午夜精品视频| 99re成人精品视频| 中文字幕精品在线不卡| 国模精品娜娜一二三区| 亚洲欧洲在线观看av| 亚洲激情网址| 一区二区三区欧美视频| 亚洲一区二区动漫| 亚洲成人一区二区在线观看| 日本电影欧美片| 久久电影网电视剧免费观看| 欧美久久一区二区| 粉嫩av一区二区三区在线播放| 337p日本欧洲亚洲大胆精品| 欧美激情91| 伊人婷婷欧美激情| 欧美专区在线| 韩国一区二区三区| 日韩精品一区二区三区三区免费| 不卡高清视频专区| 日韩毛片精品高清免费| 国产一区二区黄色| 裸体一区二区三区| 日韩精品在线一区| 精品999在线观看| 亚洲图片自拍偷拍| 欧美日韩综合一区| 99re6这里只有精品视频在线观看| 国产精品久久久久久久久快鸭| 国产模特精品视频久久久久| 久久97超碰色| 久久丝袜美腿综合| 欧美精选一区| 亚洲香蕉伊在人在线观| 色久优优欧美色久优优| 激情综合亚洲精品| 久久天天做天天爱综合色| 亚洲人人精品| 久久99精品久久久久久国产越南| 国产亚洲人成网站| 亚洲国产高清视频| 日本欧美加勒比视频| 欧美一区二区三区男人的天堂| 欧美一区亚洲| 亚洲成人资源网| 欧美一二三四区在线| 激情婷婷亚洲| 久久99蜜桃精品| 国产三级精品在线| 久久国产精品亚洲77777| 国产精品一区二区在线看| 中文在线免费一区三区高中清不卡| 亚洲欧美日韩精品综合在线观看| 国产精品18久久久久久久久| 国产精品成人免费在线| 欧美网站大全在线观看| 午夜久久美女| 捆绑调教美女网站视频一区| 国产女同性恋一区二区| 一本色道a无线码一区v| 97久久精品人人爽人人爽蜜臀| 亚洲一区二区美女| 日韩欧美在线1卡| 亚洲免费中文| 成人av网站免费观看| 亚洲成人一区二区在线观看| 久久免费电影网| 老司机午夜精品视频在线观看| 欧美chengren| 精品系列免费在线观看| 国产精品二三区| 欧美日产在线观看| 亚洲每日在线| 成人视屏免费看| 亚洲高清一区二区三区| 久久新电视剧免费观看| 色婷婷久久一区二区三区麻豆| 欧美在线亚洲| 久久不见久久见免费视频7| 国产精品视频在线看| 欧美区一区二区三区| 亚洲激情女人| 播五月开心婷婷综合| 天天操天天干天天综合网| 久久久久国产精品免费免费搜索| 老司机午夜免费精品视频| 欧美日韩三级| 国产乱色国产精品免费视频| 一区二区三区在线视频免费| 26uuu精品一区二区| 亚洲丝袜制服诱惑| 久久电影一区| 国模精品娜娜一二三区| 国产成人在线视频网站| 亚洲资源中文字幕| 久久久久青草大香线综合精品| 欧美性生活影院| 亚洲深夜影院| 91色婷婷久久久久合中文| 精品中文字幕一区二区小辣椒| |精品福利一区二区三区| 日韩免费电影网站| 欧美在线观看视频在线| 国产精品一页| 亚洲国产91| 欧美chengren| 国产91丝袜在线播放0| 美女视频黄 久久| 亚洲成人tv网| 亚洲欧美日韩成人高清在线一区| 精品国产电影一区二区| 欧美丰满一区二区免费视频| 老妇喷水一区二区三区| 最新日韩在线| 午夜精品亚洲一区二区三区嫩草| 成人一区二区三区中文字幕| 久久国产尿小便嘘嘘尿| 日本不卡在线视频| 久久久精品天堂| 久久久久国产精品一区三寸| 国内自拍一区| 欧美啪啪一区| 不卡的电影网站| 国产高清精品网站| 国产精品动漫网站| 国产偷v国产偷v亚洲高清| 日韩精品综合一本久道在线视频| 欧美日韩精品系列| 91久久精品网| 久久综合亚州| 久久国产主播精品| 国产亚洲一区在线播放| 9国产精品视频| 99热这里只有成人精品国产| 国产精品国产一区二区| 91影院在线免费观看| 成a人片亚洲日本久久| 国产成人免费在线观看不卡| 黄一区二区三区| 日韩成人免费在线| 午夜一区二区三区在线观看| 一区二区三区精品在线观看| 亚洲精品高清在线观看| 亚洲特级片在线| 亚洲欧美国产毛片在线| 最新国产成人在线观看| 亚洲色图丝袜美腿| 有坂深雪av一区二区精品| 亚洲综合一二区| 亚洲成a天堂v人片| 日韩国产高清在线| 秋霞午夜鲁丝一区二区老狼| 另类中文字幕网| 国产一区在线视频| 国产成人精品免费一区二区| 福利一区二区在线观看| 成人黄色软件下载| 成人激情av网| 91视频一区二区| 欧美日韩一区二区三区在线观看免 | 亚洲天堂偷拍| 极品日韩av| 亚洲一区二区三区免费观看| 美女亚洲精品| 欧美日韩激情在线| 欧美va亚洲va| 国产精品久久久久久亚洲毛片| 亚洲情趣在线观看| 丝袜美腿高跟呻吟高潮一区|