精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

深入理解并發(fā)編程藝術(shù)之JVM內(nèi)存模型

開發(fā) 前端
Java語言無須任何同步手段保障就能成立的先行發(fā)生規(guī)則有且只有上面這些,下面演示一下如何使用這些規(guī)則去判定操作間是否具備順序性,對于讀寫共享變量的操作來說,就是線程是否安全。

java內(nèi)存模型由來

我們知道不同的計(jì)算機(jī)硬件和操作系統(tǒng)的,所遵循的規(guī)范以及計(jì)算機(jī)內(nèi)存模型是有區(qū)別的,也就意味著我們開發(fā)的程序放在某個(gè)計(jì)算機(jī)硬件和操作系統(tǒng)上運(yùn)行是正常的,而在另一個(gè)計(jì)算機(jī)硬件和操作系統(tǒng)上運(yùn)行就存在安全問題。

《Java 虛擬機(jī)規(guī)范》中曾試圖定義一種“Java 內(nèi)存模型”來屏蔽各種硬件和操作系統(tǒng)的內(nèi)存訪問差異,以實(shí)現(xiàn)讓 Java 程序在各種平臺(tái)下都能達(dá)到一致的內(nèi)存訪問效果,但是定義 Java 內(nèi)存模型并非一件容易的事情,這個(gè)模型必須定義得足夠嚴(yán)謹(jǐn),才能讓 Java 的并發(fā)內(nèi)存訪 問操作不會(huì)產(chǎn)生歧義;但是也必須定義得足夠?qū)捤?,使得虛擬機(jī)的實(shí)現(xiàn)能有足夠的自由空間去利用硬件的各種特性(寄存器、高速緩存和指令集中某些特有的指令)來獲取更好的執(zhí)行速度。為了獲得更好的執(zhí)行效能,Java 內(nèi)存模型并沒有限制執(zhí)行引擎使用處理器的特定寄存器或緩存來和主內(nèi)存進(jìn)行交互,也沒有限制即時(shí)編譯器是否要進(jìn)行調(diào)整代碼執(zhí)行順序這類優(yōu)化措施。經(jīng)過長時(shí)間的驗(yàn)證和修補(bǔ),直至 JDK 5(實(shí)現(xiàn)了 JSR-133)發(fā)布后,Java 內(nèi)存模型才終于成熟、完善起來了。

講到這里java內(nèi)存模型的概念是什么呢?

Java 內(nèi)存模型(Java Memory Model 簡稱 JMM)是一種抽象的概念,并不真實(shí)存在,它主要目的是圍繞原子性、可見性和有序性這幾種并發(fā)問題定義程序中各種變量的訪問規(guī)則,即關(guān)注在虛擬機(jī)中把變量值存儲(chǔ)到內(nèi)存和從內(nèi)存中取出變量值這樣的底層細(xì)節(jié)。此處的變量與 Java 編程中所說的變量有所區(qū)別,它包括了實(shí)例字段、靜態(tài)字段和構(gòu)成數(shù)組對象的元素,但是不包括局部變量與方法參數(shù),因?yàn)楹笳呤蔷€程私有的,不會(huì)被共享,自然就不會(huì)存在競爭問題。JVM運(yùn)行程序的實(shí)體是線程,而每個(gè)線程創(chuàng)建時(shí)JVM都會(huì)為其創(chuàng)建一個(gè)工作內(nèi)存(有些地方稱為棧空間),用于存儲(chǔ)線程私有的數(shù)據(jù),而Java內(nèi)存模型中規(guī)定所有變量都存儲(chǔ)在主內(nèi)存,主內(nèi)存是共享內(nèi)存區(qū)域,所有線程都可以訪問,但線程對變量的操作(讀取賦值等)必須在工作內(nèi)存中進(jìn)行,首先要將變量從主內(nèi)存拷貝的自己的工作內(nèi)存空間,然后對變量進(jìn)行操作,操作完成后再將變量寫回主內(nèi)存,不能直接操作主內(nèi)存中的變量,工作內(nèi)存中存儲(chǔ)著主內(nèi)存中的變量副本拷貝,前面說過,工作內(nèi)存是每個(gè)線程的私有數(shù)據(jù)區(qū)域,因此不同的線程間無法訪問對方的工作內(nèi)存,線程間的通信(傳值)必須通過主內(nèi)存來完成。

主內(nèi)存主要存儲(chǔ)的是Java實(shí)例對象,所有線程創(chuàng)建的實(shí)例對象都存放在主內(nèi)存中,不管該實(shí)例對象是成員變量還是方法中的本地變量(也稱局部變量),當(dāng)然也包括了共享的類信息、常量、靜態(tài)變量。由于是共享數(shù)據(jù)區(qū)域,多條線程對同一個(gè)變量進(jìn)行訪問可能會(huì)發(fā)生線程安全問題。

工作內(nèi)存主要存儲(chǔ)當(dāng)前方法的所有本地變量信息(工作內(nèi)存中存儲(chǔ)著主內(nèi)存中的變量副本拷貝),每個(gè)線程只能訪問自己的工作內(nèi)存,即線程中的本地變量對其它線程是不可見的,就算是兩個(gè)線程執(zhí)行的是同一段代碼,它們也會(huì)各自在自己的工作內(nèi)存中創(chuàng)建屬于當(dāng)前線程的本地變量,當(dāng)然也包括了字節(jié)碼行號(hào)指示器、相關(guān)Native方法的信息。注意由于工作內(nèi)存是每個(gè)線程的私有數(shù)據(jù),線程間無法相互訪問工作內(nèi)存,因此存儲(chǔ)在工作內(nèi)存的數(shù)據(jù)不存在線程安全問題。

根據(jù)JVM虛擬機(jī)規(guī)范主內(nèi)存與工作內(nèi)存的數(shù)據(jù)存儲(chǔ)類型以及操作方式,對于一個(gè)實(shí)例對象中的成員方法而言,如果方法中包含本地變量是基本數(shù)據(jù)類型(boolean,byte,short,char,int,long,float,double),將直接存儲(chǔ)在工作內(nèi)存的幀棧結(jié)構(gòu)中,但倘若本地變量是引用類型,那么該變量的引用會(huì)存儲(chǔ)在功能內(nèi)存的幀棧中,而對象實(shí)例將存儲(chǔ)在主內(nèi)存(共享數(shù)據(jù)區(qū)域,堆)中。但對于實(shí)例對象的成員變量,不管它是基本數(shù)據(jù)類型或者包裝類型(Integer、Double等)還是引用類型,都會(huì)被存儲(chǔ)到堆區(qū)。至于static變量以及類本身相關(guān)信息將會(huì)存儲(chǔ)在主內(nèi)存中。需要注意的是,在主內(nèi)存中的實(shí)例對象可以被多線程共享,倘若兩個(gè)線程同時(shí)調(diào)用了同一個(gè)對象的同一個(gè)方法,那么兩條線程會(huì)將要操作的數(shù)據(jù)拷貝一份到自己的工作內(nèi)存中,執(zhí)行完成操作后才刷新到主內(nèi)存

java內(nèi)存模型中的問題

我們java開發(fā)中三個(gè)并發(fā)問題原子性問題,可見性問題,指令重排問題

原子性問題

原子性就是指該操作是不可再分的。不論是多核還是單核,具有原子性的量,同一時(shí)刻只能有一個(gè)線程來對它進(jìn)行操作。簡而言之,在整個(gè)操作過程中不會(huì)被線程調(diào)度器中斷的操作,都可認(rèn)為是原子性。

可見性問題

可見性就是指當(dāng)一個(gè)線程修改了共享變量的值時(shí),其他線程能夠立即得知這個(gè)修改。

指令重排問題

指令重排序:java語言規(guī)范規(guī)定JVM線程內(nèi)部維持順序化語義。即只要程序的最終結(jié)果與它順序化情況的結(jié)果相等,那么指令的執(zhí)行順序可以與代碼順序不一致,此過程叫指令的重排序。指令重排序的意義是什么:JVM能根據(jù)處理器特性(CPU多級(jí)緩存系統(tǒng)、多核處理器等)適當(dāng)?shù)膶C(jī)器指令進(jìn)行重排序,使機(jī)器指令能更符合CPU的執(zhí)行特性,最大限度的發(fā)揮機(jī)器性能,但是指令重排會(huì)遵循as-if-serial語義。as-if-serial語義的意思是:不管怎么重排序,程序的執(zhí)行結(jié)果不能被改變。編譯器、runtime和處理器都必須遵守as-if-serial語義,為了遵守as-if-serial語義,編譯器和處理器不會(huì)對存在數(shù)據(jù)依賴關(guān)系的操作做重排序,因?yàn)檫@種重排序會(huì)改變執(zhí)行結(jié)果。但是,如果操作之間不存在數(shù)據(jù)依賴關(guān)系,這些操作就可能被編譯器和處理器重排序。何為依賴關(guān)系:譬如指令1把地址A中的值加10,指令2 把地址A中的值乘以2,指令3把地址B中的值減去3,這時(shí)指令1和指令2是有依賴的,它們之間的順序不能重排——(A+10)2與A2+10顯然不相等,但指令3可以重排到指令1、2之前或者中間,只要保證 處理器執(zhí)行后面依賴到A、B值的操作時(shí)能獲取正確的A和B值即可。

Java內(nèi)存模型具備一些先天的“有序性”,即不需要通過任何手段就能夠得到保證的有序性,這個(gè)通常也稱為happens-before 原則。如果兩個(gè)操作的執(zhí)行次序無法從happens-before原則推導(dǎo)出來,那么它們就不能保證它們的有序性,虛擬機(jī)可以隨意地對它們進(jìn)行重排序。happens-before原則后面再介紹。

下圖為從源碼到最終執(zhí)行的指令序列示意圖:

圖片

java內(nèi)存模型如何解決問題

為了解決這種線程安全問題,針對一個(gè)變量如何從主內(nèi)存拷貝到工作內(nèi)存、如何從工作內(nèi)存同步到主內(nèi)存之間的實(shí)現(xiàn)細(xì)節(jié),Java 內(nèi)存模型定義了以下八種操作來完成。

數(shù)據(jù)同步八大原子操作

(1)lock(鎖定):作用于主內(nèi)存的變量,把一個(gè)變量標(biāo)記為一條線程獨(dú)占狀態(tài)

(2)unlock(解鎖):作用于主內(nèi)存的變量,把一個(gè)處于鎖定狀態(tài)的變量釋放出來,釋放后的變量才可以被其他線程鎖定

(3)read(讀取):作用于主內(nèi)存的變量,把一個(gè)變量值從主內(nèi)存?zhèn)鬏數(shù)骄€程的工作內(nèi)存中,以便隨后的 load 動(dòng)作使用

(4)load(載入):作用于工作內(nèi)存的變量,它把 read 操作從主內(nèi)存中得到的變量值放入工作內(nèi)存的變量副本中

(5)use(使用):作用于工作內(nèi)存的變量,把工作內(nèi)存中的一個(gè)變量值傳遞給執(zhí)行引擎

(6)assign(賦值):作用于工作內(nèi)存的變量,它把一個(gè)從執(zhí)行引擎接收到的值賦給工作內(nèi)存的變量

(7)store(存儲(chǔ)):作用于工作內(nèi)存的變量,把工作內(nèi)存中的一個(gè)變量的值傳送到主內(nèi)存中,以便隨后的 write 的操作

(8)write(寫入):作用于工作內(nèi)存的變量,它把 store 操作從工作內(nèi)存中的一個(gè)變量的值傳送到主內(nèi)存的變量中

如果要把一個(gè)變量從主內(nèi)存拷貝到工作內(nèi)存,那就要按順序執(zhí)行read和load操作,如果要把變量從 工作內(nèi)存同步回主內(nèi)存,就要按順序執(zhí)行store和write操作。注意,Java內(nèi)存模型只要求上述兩個(gè)操作 必須按順序執(zhí)行,但不要求是連續(xù)執(zhí)行。也就是說read與load之間、store與write之間是可插入其他指令 的,如對主內(nèi)存中的變量a、b進(jìn)行訪問時(shí),一種可能出現(xiàn)的順序是read a、read b、load b、load a。

除此 之外,Java內(nèi)存模型還規(guī)定了在執(zhí)行上述8種基本操作時(shí)必須滿足如下規(guī)則:

1.不允許 read 和 load、store和 write操作之一單獨(dú)出現(xiàn),即不允許一個(gè)變量從主內(nèi)存讀取了但工作內(nèi)存不接受,或者工作內(nèi)存發(fā)起回寫了但主內(nèi)存不接受的情況出現(xiàn)。

2.不允許一個(gè)線程丟棄它最近的assign 操作,即變量在工作內(nèi)存中改變了之后必須把該變化同步回主內(nèi)存。

3.不允許一個(gè)線程無原因地(沒有發(fā)生過任何 assign 操作)把數(shù)據(jù)從線程的工作內(nèi)存同步回主內(nèi)存中。

4.一個(gè)新的變量只能在主內(nèi)存中“誕生”,不允許在工作內(nèi)存中直接使用一個(gè)未被初始化(load 或 assign)的變量,換句話說就是對一個(gè)變量實(shí)施 use、store 操作之前,必須先執(zhí)行 assign 和 load 操作。

5.一個(gè)變量在同一個(gè)時(shí)刻只允許一條線程對其進(jìn)行 lock 操作,但lock操作可以被同一條線程重復(fù)執(zhí)行多次,多次執(zhí)行 lock 后,只有執(zhí)行相同次數(shù)的 unlock 操作,變量才會(huì)被解鎖。

6.如果對一個(gè)變量執(zhí)行l(wèi)ock操作,那將會(huì)清空工作內(nèi)存中此變量的值,在執(zhí)行引擎使用這個(gè)變量前,需要重新執(zhí)行l(wèi)oad或assign操作以初始化變量的值。

7.如果一個(gè)變量事先沒有被lock操作鎖定,那就不允許對它執(zhí)行unlock操作,也不允許去unlock一個(gè)被其他線程鎖定的變量。

8.對一個(gè)變量執(zhí)行unlock操作之前,必須先把此變量同步回主內(nèi)存中(執(zhí)行store、write操作)。

8大原子操作long和double類型

Java內(nèi)存模型要求lock、unlock、read、load、assign、use、store、write這八種操作都具有原子性, 但是對于64位的數(shù)據(jù)類型(long和double),在模型中特別定義了一條寬松的規(guī)定:允許虛擬機(jī)將沒有 被volatile修飾的64位數(shù)據(jù)的讀寫操作劃分為兩次32位的操作來進(jìn)行,即允許虛擬機(jī)實(shí)現(xiàn)自行選擇是否 要保證64位數(shù)據(jù)類型的load、store、read和write這四個(gè)操作的原子性,這就是所謂的“l(fā)ong和double的非原子性協(xié)定”。

如果有多個(gè)線程共享一個(gè)并未聲明為volatile的long或double類型的變量,并且同時(shí)對它們進(jìn)行讀取和修改操作,那么某些線程可能會(huì)讀取到一個(gè)既不是原值,也不是其他線程修改值的代表了“半個(gè)變量”的數(shù)值。不過這種讀取到“半個(gè)變量”的情況是非常罕見的,經(jīng)過實(shí)際測試,在目前主流平臺(tái)下商 用的64位Java虛擬機(jī)中并不會(huì)出現(xiàn)非原子性訪問行為,但是對于32位的Java虛擬機(jī),譬如比較常用的32位x86平臺(tái)下的HotSpot虛擬機(jī),對long類型的數(shù)據(jù)確實(shí)存在非原子性訪問的風(fēng)險(xiǎn)。

從JDK9起,HotSpot增加了一個(gè)實(shí)驗(yàn)性的參數(shù)-XX:+AlwaysAtomicAccesses來約束虛擬機(jī)對所有數(shù)據(jù)類型進(jìn)行原子性的訪問。而針對double類型,由于現(xiàn)代中央處理器中一般都包含專門用于處理浮點(diǎn)數(shù)據(jù)的浮點(diǎn)運(yùn)算器,用來專門處理單、雙精度的浮點(diǎn)數(shù)據(jù),所以哪怕是32位虛擬機(jī)中通常也不會(huì)出現(xiàn)非原子性訪問的問題,實(shí)際測試也證實(shí)了這一點(diǎn)。筆者的看法是,在實(shí)際開發(fā)中,除非該數(shù)據(jù)有明確可知的線程競爭,否則我們在編寫代碼時(shí)一般不需要因?yàn)檫@個(gè)原因刻意把用到的long和double變量專門聲明為volatile。

volatile關(guān)鍵字

除了8大原子操作Java內(nèi)存模型還對volatile關(guān)鍵字定義了特殊規(guī)則:

假定 T 表示 一個(gè)線程,V 和 W 分別表示兩個(gè) volatile 型變量,那么在進(jìn)行 read、load、use、assign、store 和 write 操作 時(shí)需要滿足如下規(guī)則:

1.只有當(dāng)線程 T 對變量 V 執(zhí)行的前一個(gè)動(dòng)作是 load 的時(shí)候,線程 T 才能對變量 V 執(zhí)行 use 動(dòng)作;并且, 只有當(dāng)線程 T 對變量 V 執(zhí)行的后一個(gè)動(dòng)作是 use 的時(shí)候,線程 T 才能對變量 V 執(zhí)行 load 動(dòng)作。線程 T 對變量 V 的 use 動(dòng)作可以認(rèn)為是和線程 T 對變量 V 的 load、read 動(dòng)作相關(guān)聯(lián)的,必須連續(xù)且一起出現(xiàn)。這條規(guī)則要求在工作內(nèi)存中,每次使用 V 前都必須先從主內(nèi)存刷新最新的值,用于保證能看見其 他線程對變量 V 所做的修改。

2.只有當(dāng)線程 T 對變量 V 執(zhí)行的前一個(gè)動(dòng)作是 assign 的時(shí)候,線程 T 才能對變量 V 執(zhí)行 store 動(dòng)作;并 且,只有當(dāng)線程 T 對變量 V 執(zhí)行的后一個(gè)動(dòng)作是 store 的時(shí)候,線程 T 才能對變量 V 執(zhí)行 assign 動(dòng)作。線程 T 對變量 V 的 assign 動(dòng)作可以認(rèn)為是和線程 T 對變量 V 的 store、write 動(dòng)作相關(guān)聯(lián)的,必須連續(xù)且一起出現(xiàn)。這條規(guī)則要求在工作內(nèi)存中,每次修改V后都必須立刻同步回主內(nèi)存中,用于保證其他線程可以 看到自己對變量V所做的修改。

3.假定動(dòng)作A是線程T對變量V實(shí)施的use或assign 動(dòng)作,假定動(dòng)作F 是和動(dòng)作A相關(guān)聯(lián)的load或store動(dòng)作,假定動(dòng)作P是和動(dòng)作F相應(yīng)的對變量V的read或write動(dòng)作;與此類似,假定動(dòng)作B是線程T對變量W實(shí)施的use或assign動(dòng)作,假定動(dòng)作G是和動(dòng)作B相關(guān)聯(lián)的load或store 動(dòng)作,假定動(dòng)作Q是和動(dòng)作G相應(yīng)的對變量W的read或 write動(dòng)作。如果A先于B,那么P先于Q。這條規(guī)則要求volatile修飾的變量不會(huì)被指令重排序優(yōu)化,從而保證代碼的執(zhí)行順序與程序的順序 相同。

volatile關(guān)鍵字可以解決指令重排和可見性問題但是解決不了原字性問題,synchronized可以解決原子性問題,可見性問題,指令重排問題,后面講會(huì)詳細(xì)說一下volatile關(guān)鍵字和synchronized。

這8種內(nèi)存訪問操作以及上述規(guī)則的限定以及jvm內(nèi)存模型對volatile 的一些特殊規(guī)定,就已經(jīng)能準(zhǔn)確地描述出Java程序中哪些內(nèi)存訪問操作在并發(fā)下才是安全的?;诶斫怆y度和嚴(yán)謹(jǐn)性考慮,最新的JSR-133文檔中,已經(jīng)放棄了采用這8種操作去定義Java內(nèi)存模型的訪問協(xié)議,縮減為4種(僅是描述方式改變了,Java 內(nèi)存模型并沒有改變)。

先行發(fā)生原則

這8種內(nèi)存訪問操作以及上述規(guī)則限定,再加上稍后會(huì)介紹的專門針對volatile的一些特殊規(guī)定,就已經(jīng)能準(zhǔn)確地描述出Java程序中哪些內(nèi)存訪問操作在并發(fā)下才是安全的。這種定義相當(dāng)嚴(yán)謹(jǐn),但也是極為煩瑣,實(shí)踐起來更是無比麻煩。如果在代碼中必須考慮以上定義才能確定并發(fā)訪問下是否安全,那就太麻煩了,好在后來這種定義的一個(gè)等效判斷原則——先行發(fā)生原則的提出解決這中困惑, 如果Java內(nèi)存模型中所有的有序性都僅靠volatile和synchronized來完成,那么有很多操作都將會(huì)變 得非常啰嗦,但是我們在編寫Java并發(fā)代碼的時(shí)候并沒有察覺到這一點(diǎn),這是因?yàn)镴ava語言中有一 個(gè)“先行發(fā)生”(Happens-Before)的原則。這個(gè)原則非常重要,它是判斷數(shù)據(jù)是否存在競爭,線程是否安全的非常有用的手段。依賴這個(gè)原則,我們可以通過幾條簡單規(guī)則一攬子解決并發(fā)環(huán)境下兩個(gè)操 作之間是否可能存在沖突的所有問題,而不需要陷入Java內(nèi)存模型苦澀難懂的定義之中。現(xiàn)在就來看看“先行發(fā)生”原則指的是什么。先行發(fā)生是Java內(nèi)存模型中定義的兩項(xiàng)操作之間的偏序關(guān)系,比如說操作A先行發(fā)生于操作B,其實(shí)就是說在發(fā)生操作B之前,操作A產(chǎn)生的影響能被操作B 觀察到,“影響”包括修改了內(nèi)存中共享變量的值、發(fā)送了消息、調(diào)用了方法等。這句話不難理解,但它意味著什么呢?我們可以舉個(gè)例子來說明一下。如代碼清單12-8所示的這三條偽代碼。

// 以下操作在線程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還沒登場,線程A操作結(jié)束之后沒有其他線程會(huì)修改變量i的值。現(xiàn)在再來考慮 線程C,我們依然保持線程A和B之間的先行發(fā)生關(guān)系,而C出現(xiàn)在線程A和B的操作之間,但是C與B沒 有先行發(fā)生關(guān)系,那j的值會(huì)是多少呢?答案是不確定!1和2都有可能,因?yàn)榫€程C對變量i的影響可能 會(huì)被線程B觀察到,也可能不會(huì),這時(shí)候線程B就存在讀取到過期數(shù)據(jù)的風(fēng)險(xiǎn),不具備多線程安全性。下面是Java內(nèi)存模型下一些“天然的”先行發(fā)生關(guān)系,這些先行發(fā)生關(guān)系無須任何同步器協(xié)助就已 經(jīng)存在,可以在編碼中直接使用。如果兩個(gè)操作之間的關(guān)系不在此列,并且無法從下列規(guī)則推導(dǎo)出來,則它們就沒有順序性保障,虛擬機(jī)可以對它們隨意地進(jìn)行重排序。

·程序次序規(guī)則(Program Order Rule):在一個(gè)線程內(nèi),按照控制流順序,書寫在前面的操作先行 發(fā)生于書寫在后面的操作。注意,這里說的是控制流順序而不是程序代碼順序,因?yàn)橐紤]分支、循 環(huán)等結(jié)構(gòu)。

·管程鎖定規(guī)則(Monitor Lock Rule):一個(gè)unlock操作先行發(fā)生于后面對同一個(gè)鎖的lock操作。這 里必須強(qiáng)調(diào)的是“同一個(gè)鎖”,而“后面”是指時(shí)間上的先后。

·volatile變量規(guī)則(Volatile Variable Rule):對一個(gè)volatile變量的寫操作先行發(fā)生于后面對這個(gè)變量 的讀操作,這里的“后面”同樣是指時(shí)間上的先后。

·線程啟動(dòng)規(guī)則(Thread Start Rule):Thread對象的start()方法先行發(fā)生于此線程的每一個(gè)動(dòng)作。

·線程終止規(guī)則(Thread Termination Rule):線程中的所有操作都先行發(fā)生于對此線程的終止檢 測,我們可以通過Thread::join()方法是否結(jié)束、Thread::isAlive()的返回值等手段檢測線程是否已經(jīng)終止 執(zhí)行。

·線程中斷規(guī)則(Thread Interruption Rule):對線程interrupt()方法的調(diào)用先行發(fā)生于被中斷線程 的代碼檢測到中斷事件的發(fā)生,可以通過Thread::interrupted()方法檢測到是否有中斷發(fā)生。

·對象終結(jié)規(guī)則(Finalizer Rule):一個(gè)對象的初始化完成(構(gòu)造函數(shù)執(zhí)行結(jié)束)先行發(fā)生于它的 finalize()方法的開始。

·傳遞性(Transitivity):如果操作A先行發(fā)生于操作B,操作B先行發(fā)生于操作C,那就可以得出 操作A先行發(fā)生于操作C的結(jié)論。

Java語言無須任何同步手段保障就能成立的先行發(fā)生規(guī)則有且只有上面這些,下面演示一下如何使用這些規(guī)則去判定操作間是否具備順序性,對于讀寫共享變量的操作來說,就是線程是否安全。讀者還可以從下面這個(gè)例子中感受一下“時(shí)間上的先后順序”與“先行發(fā)生”之間有什么不同。演示例子如以下代碼所示。

private int value = 0; 
pubilc void setValue(int value){ 
this.value = value; 
}
public int getValue(){ 
return value; 
}

代碼中顯示的是一組再普通不過的getter/setter方法,假設(shè)存在線程A和B,線程A先(時(shí) 間上的先后)調(diào)用了setValue(1),然后線程B調(diào)用了同一個(gè)對象的getValue(),那么線程B收到的返回值是什么?

我們依次分析一下先行發(fā)生原則中的各項(xiàng)規(guī)則:

1.由于兩個(gè)方法分別由線程A和B調(diào)用,不在一個(gè)線程中,所以程序次序規(guī)則在這里不適用;

2.由于沒有同步塊,自然就不會(huì)發(fā)生lock和unlock操作,所以管程鎖定規(guī)則不適用;

3.由于value變量沒有被volatile關(guān)鍵字修飾,所以volatile變量規(guī)則不適用;

4.后面的線程啟動(dòng)、終止、中斷規(guī)則和對象終結(jié)規(guī)則也和這里完全沒有關(guān)系。

5.因?yàn)闆]有一個(gè)適用的先行發(fā)生規(guī)則,所以最后一條傳遞性也無從談起,因此我們可以判定,盡管線程A在操作時(shí)間上先于線程B,但是無法確定線程B中g(shù)etValue()方法的返回結(jié)果,換句話說,這里面的操作不是線程安全的。

那怎么修復(fù)這個(gè)問題呢?我們至少有兩種比較簡單的方案可以選擇:

1.要么把getter/setter方法都定義為synchronized方法,這樣就可以套用管程鎖定規(guī)則;

2.要么把value定義為volatile變量,由于setter方法對value的修改不依賴value的原值,滿足volatile關(guān)鍵字使用場景,這樣就可以套用volatile變量規(guī)則來 實(shí)現(xiàn)先行發(fā)生關(guān)系。

通過上面的例子,我們可以得出結(jié)論:一個(gè)操作“時(shí)間上的先發(fā)生”不代表這個(gè)操作會(huì)是“先行發(fā)生”。那如果一個(gè)操作“先行發(fā)生”,是否就能推導(dǎo)出這個(gè)操作必定是“時(shí)間上的先發(fā)生”呢?很遺憾,這個(gè)推論也是不成立的。

一個(gè)典型的例子就是多次提到的“指令重排序”,如下代碼所示:

int i = 1; 
int j = 2;

代碼所示的兩條賦值語句在同一個(gè)線程之中,根據(jù)程序次序規(guī)則,“int i=1”的操作先行發(fā)生于“int j=2”,但是“int j=2”的代碼完全可能先被處理器執(zhí)行,這并不影響先行發(fā)生原則的正確性,因?yàn)槲覀冊谶@條線程之中沒有辦法感知到這一點(diǎn)。

上面兩個(gè)例子綜合起來證明了一個(gè)結(jié)論:時(shí)間先后順序與先行發(fā)生原則之間基本沒有因果關(guān)系,所以我們衡量并發(fā)安全問題的時(shí)候不要受時(shí)間順序的干擾,一切必須以先行發(fā)生原則為準(zhǔn)。

責(zé)任編輯:武曉燕 來源: 碼農(nóng)本農(nóng)
相關(guān)推薦

2023-11-05 12:05:35

JVM內(nèi)存

2023-10-27 07:47:37

計(jì)算機(jī)內(nèi)存模型

2021-09-08 17:42:45

JVM內(nèi)存模型

2020-12-11 07:32:45

編程ThreadLocalJava

2020-11-13 08:42:24

Synchronize

2021-11-26 00:00:48

JVM內(nèi)存區(qū)域

2022-10-12 07:53:46

并發(fā)編程同步工具

2015-12-28 11:41:57

JVM內(nèi)存區(qū)域內(nèi)存溢出

2024-05-24 14:35:49

2024-12-31 09:00:12

Java線程狀態(tài)

2019-06-25 10:32:19

UDP編程通信

2022-06-22 08:02:11

CPU操作系統(tǒng)Java

2015-03-24 13:28:52

Java Java Strin內(nèi)存模型

2021-02-17 11:25:33

前端JavaScriptthis

2021-09-24 08:10:40

Java 語言 Java 基礎(chǔ)

2021-07-26 07:47:37

無鎖編程CPU

2024-03-19 14:14:27

線程開發(fā)

2019-10-11 08:41:35

JVM虛擬機(jī)語言

2021-09-18 06:56:01

JavaCAS機(jī)制

2023-09-19 22:47:39

Java內(nèi)存
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

欧美国产三级| 欧美黄色a视频| 久久亚洲精品小早川怜子| 人妖精品videosex性欧美| 中国特黄一级片| 国产美女亚洲精品7777| 亚洲福利国产精品| 日韩精品国内| 亚洲成a人片77777精品| 久久久人人人| 毛片精品免费在线观看| 黄瓜视频污在线观看| 成人黄色理论片| 欧美日韩国产在线看| 一区二区三区免费看| 手机在线精品视频| 经典三级在线一区| 欧美在线视频一区二区| 日韩a级片在线观看 | 韩日午夜在线资源一区二区 | 日韩一二三四区| 久久久久狠狠高潮亚洲精品| av在线麻豆| 国产日韩欧美麻豆| 国产欧美日韩伦理| 99免费在线视频| 日韩高清不卡在线| 69久久夜色精品国产7777 | 午夜激情综合网| 麻豆md0077饥渴少妇| 成人高清网站| 久久综合久色欧美综合狠狠| 5g国产欧美日韩视频| 中文字幕在线一| 久久精品伊人| 97福利一区二区| 欧美日韩一级大片| 2023国产精品久久久精品双| 中文字幕欧美日韩va免费视频| 性久久久久久久久久| 精品嫩草影院| 欧美第一区第二区| 九色91porny| 91麻豆精品国产综合久久久| 日本韩国欧美在线| 色综合av综合无码综合网站| 97超碰在线免费| 一区二区不卡在线视频 午夜欧美不卡在| 亚洲国产欧美日韩| а√天堂中文在线资源bt在线| 91丝袜呻吟高潮美腿白嫩在线观看| 91免费在线观看网站| a级片免费观看| 国产一区免费电影| 亚洲一区二区三区乱码aⅴ蜜桃女| 一本一道人人妻人人妻αv| 青青草国产精品97视觉盛宴| 国产99视频在线观看| 国产91国语对白在线| 玖玖在线精品| 国产福利视频一区| 中国女人一级一次看片| 毛片基地黄久久久久久天堂| 国产精品美女www爽爽爽视频| 黄色污污视频软件| 麻豆精品一区二区综合av| 国产日韩欧美在线| 国产成人精品毛片| 成人激情黄色小说| 久久久久一区二区| 韩国三级在线观看久| 国产日产亚洲精品系列| 亚洲欧美久久234| caopo在线| 亚洲午夜电影在线观看| www精品久久| 精品91久久| 欧美日韩不卡在线| 欧美熟妇精品一区二区| 日韩最新在线| 日韩中文字幕在线观看| 久久久一二三区| 免费亚洲一区| 成人福利免费观看| 成 人 免费 黄 色| 91丨九色丨尤物| 亚洲一区二区高清视频| 伊人福利在线| 91久久免费观看| а 天堂 在线| 欧美人妖在线观看| 日韩资源在线观看| 国产成年人免费视频| 视频一区欧美日韩| 亚洲专区国产精品| 欧美黄色小说| 亚洲视频香蕉人妖| 国产日产欧美视频| 99久久久国产| 亚洲男人第一网站| 欧美成人综合色| 美女黄色成人网| 3d蒂法精品啪啪一区二区免费| 天天操天天操天天操| 国产精品传媒在线| 国产精品又粗又长| 综合久久av| 亚洲精品中文字幕av| 青青青在线免费观看| 久久av一区二区三区| 亚洲qvod图片区电影| 欧美白人做受xxxx视频| 亚洲精品ww久久久久久p站| 国产麻花豆剧传媒精品mv在线| 日本一区精品视频| 中文字幕亚洲激情| 亚洲另类在线观看| 国产精品99久久久久久似苏梦涵| 日韩av影视| sm久久捆绑调教精品一区| 欧美日韩国产美女| 国产肥白大熟妇bbbb视频| 国产精品草草| 亚洲伊人久久大香线蕉av| 国产毛片在线看| 懂色av中文一区二区三区天美| 在线观看一区二区三区视频| 日韩dvd碟片| 国产福利视频一区| 免费在线看v| 精品久久久视频| 无码国产精品一区二区免费式直播 | 欧美一级久久| 国产伦精品一区二区三| 在线电影福利片| 91精品国产欧美一区二区| 国产探花视频在线播放| 美女网站久久| 欧美日韩中文国产一区发布| 欧美伦理91| 欧美精品一区二区三区很污很色的| 成人在线观看免费完整| 久久99精品久久久久久动态图 | 欧美日韩亚洲一区在线观看| 成人做爰www免费看视频网站| 二区三区在线播放| 91激情五月电影| 欧美激情aaa| 久久久久久一区二区| 欧美婷婷久久| 三上悠亚亚洲一区| 国产性猛交xxxx免费看久久| 日韩国产成人在线| 亚洲国产高清aⅴ视频| av五月天在线| 日韩欧美中文| 91久久久精品| 男女在线观看视频| 亚洲精品99久久久久| 日日摸天天添天天添破| 91麻豆免费在线观看| 日韩av在线综合| 日韩电影免费网址| 国产中文字幕日韩| 亚洲性图自拍| 亚洲国产天堂久久国产91| 可以免费看的av毛片| 91一区二区三区在线观看| 成人三级视频在线播放| 精品国产乱码久久久| 91精品久久久久久久久| a免费在线观看| 亚洲国产精品yw在线观看 | 日本色护士高潮视频在线观看 | 在线观看91视频| 91香蕉一区二区三区在线观看| 国产麻豆成人传媒免费观看| 成人免费网站在线观看| 91成人在线观看国产| 久久久av一区| 丰满熟女人妻一区二区三区| 伊人久久亚洲美女图片| 久久久久久九九九九| 国精产品一区二区三区有限公司| 亚洲午夜未删减在线观看 | 日本韩国一区二区三区视频| 五月婷六月丁香| 国产高清不卡一区二区| 国产午夜伦鲁鲁| 水蜜桃精品av一区二区| 成人情视频高清免费观看电影| 性爽视频在线| 日韩午夜在线视频| 亚洲av毛片成人精品| 欧美日韩在线三级| 好吊操这里只有精品| 中文字幕一区二区三区av| 影音先锋黄色资源| 精品在线亚洲视频| 成人免费在线小视频| 亚洲成人国产| 欧洲一区二区在线| 91精品福利观看| 久久99国产精品视频| 欧美年轻男男videosbes| 久视频在线观看| 国产蜜臀av在线一区二区三区| 26uuu国产| 免费看欧美美女黄的网站| 九色自拍视频在线观看| 亚洲a在线视频| 日韩欧美亚洲精品| 日韩av影院| 爱情岛论坛亚洲入口| 久久青草免费| 国产97色在线|日韩| 波多野结衣中文字幕久久| 这里只有精品在线播放| 天天射天天操天天干| 日韩欧美在线123| 亚洲中文字幕在线观看| 一本到高清视频免费精品| xxxxxx国产| 亚洲一区自拍偷拍| 91香蕉视频在线播放| 欧美激情一区三区| 国产男男chinese网站| 成人av免费在线| 黑人无套内谢中国美女| 精品一区二区三区免费播放| 免费大片在线观看| 中文精品视频| 每日在线观看av| 伊人成综合网| 中文字幕剧情在线观看一区| 久久激情电影| 日韩精品一区二区三区外面| 猛男gaygay欧美视频| 精品国产一区二区三区麻豆免费观看完整版| 国产 日韩 欧美| 成人亚洲激情网| 亚洲我射av| 91精品久久久久久久久久入口| 成人精品电影在线| 国产精品99久久久久久人| 极品美女一区| 国产不卡一区二区在线播放| 周于希免费高清在线观看| 欧美一区二三区| 韩国成人动漫| 国产成人精品视频在线| 亚洲www免费| 国产精品女人久久久久久| se01亚洲视频| 国产精品视频播放| 成人污污www网站免费丝瓜| 91久久久久久| 伊人精品综合| 精品国产一区二区三区免费 | 在线成人免费观看| 国产又黄又大又粗的视频| 91精品国产福利在线观看| 精品人妻午夜一区二区三区四区| 精品毛片乱码1区2区3区| 人人妻人人玩人人澡人人爽| 亚洲精品丝袜日韩| 成人性生交大片免费看午夜 | 成人在线观看免费完整| 亚洲激情六月丁香| 国产成人无码精品| 在线看国产一区二区| 国产精品无码白浆高潮| 日韩一本二本av| 手机亚洲第一页| 深夜福利亚洲导航| 在线观看电影av| 日韩av免费看网站| 国产区一区二| 九九九九久久久久| 国产高清一区二区| 精品无码一区二区三区爱欲| 石原莉奈在线亚洲二区| 久久久久久久久久毛片| 99热精品国产| 免费91在线观看| 亚洲一区二区成人在线观看| 日韩在线视频不卡| 日韩丝袜情趣美女图片| 欧美日本韩国一区二区| 不卡av在线网站| 三级在线观看视频| 91欧美精品午夜性色福利在线| 欧美电影完整版在线观看| 亚洲视频小说| 亚洲激情黄色| 五月天婷婷亚洲| 91美女在线观看| 日本精品在线免费观看| 欧美午夜激情视频| www.xxxx国产| 尤物九九久久国产精品的分类| 国产白丝在线观看| 国产精品露脸自拍| 日韩伦理一区二区三区| 亚洲黄色网址在线观看| 久久永久免费| 私密视频在线观看| 亚洲欧洲av在线| av毛片在线免费观看| 精品久久久久久无| 快射视频在线观看| 国产精欧美一区二区三区| 国产劲爆久久| 强伦女教师2:伦理在线观看| 久久一日本道色综合久久| 成人区人妻精品一区二| 亚洲人成网站在线| 国产一卡二卡三卡| 日韩的一区二区| 激情网站在线| 亚洲va久久久噜噜噜| 欧美日韩国产在线观看网站 | 亚洲а∨天堂久久精品喷水| 麻豆tv在线| 国产精品中文字幕久久久| 蜜桃精品wwwmitaows| 精品视频免费在线播放| 国产一区二区免费在线| 日本猛少妇色xxxxx免费网站| 福利一区视频在线观看| 日韩在线观看视频一区| 欧美激情中文字幕乱码免费| 国产精品一区二区三区四区在线观看 | 国产黄色片免费观看| 最近2019年手机中文字幕| 性欧美hd调教| 特级西西444www大精品视频| 日韩精品1区2区3区| 手机免费看av| 在线观看国产日韩| 尤物在线视频| 国产日韩欧美黄色| 91精品国产91久久久久久密臀| 波多野结衣xxxx| 国产精品免费丝袜| 在线免费观看一级片| 最近2019年手机中文字幕| 日韩成人在线电影| 中文字幕中文字幕99| 韩国av一区二区三区在线观看 | 性做久久久久久久免费看| 丰满大乳国产精品| 久久久中文字幕| 亚洲资源网你懂的| 天堂中文视频在线| 国产精品精品国产色婷婷| 一区二区三区午夜| 久久亚洲国产成人| 99久久人爽人人添人人澡| www污在线观看| 2014亚洲片线观看视频免费| 久久久久久亚洲av无码专区| 日韩中文在线中文网在线观看| 欧美高清xxx| 成人午夜免费在线视频| gogo大胆日本视频一区| 国产一级免费视频| 北条麻妃久久精品| 综合伊人久久| 热久久精品国产| 国产精品久久久久一区二区三区 | 香蕉污视频在线观看| 亚洲香蕉在线观看| 亚洲三级电影| 777精品久无码人妻蜜桃| 国产女人18毛片水真多成人如厕 | 亚洲精品色婷婷福利天堂| 国产 日韩 欧美一区| 婷婷视频在线播放| 成人精品国产免费网站| 免费黄色av片| 另类专区欧美制服同性| 日韩激情网站| 天天综合网久久| 午夜a成v人精品| 国内精品久久久久国产| 精品国产免费人成电影在线观... 精品国产免费久久久久久尖叫 | www.日韩一区| 久久av中文字幕| 九色精品国产蝌蚪| 在线一区二区不卡| 狠狠躁夜夜躁人人躁婷婷91| 137大胆人体在线观看| 国产精品xxxx| 久久精品国产99久久6| 日本亚洲欧美在线| 精品国产拍在线观看| 偷拍亚洲精品| 少妇搡bbbb搡bbb搡打电话| 欧美在线不卡视频|