Java 內(nèi)存模型

目錄

一、Java 內(nèi)存模型的主要目標(biāo)
二酝润、主內(nèi)存和工作內(nèi)存
三梳虽、內(nèi)存件的交互操作
四、對(duì)于 volatile 型變量的特殊規(guī)則
五彰居、對(duì)于 long 和 double 型變量的特殊規(guī)則
六诚纸、原子性、可見(jiàn)性與有序性
七陈惰、先行發(fā)生原則

一畦徘、Java 內(nèi)存模型的主要目標(biāo)

Java 內(nèi)存模型的主要目標(biāo)是 定義程序中各個(gè)變量的訪(fǎng)問(wèn)規(guī)則,即在虛擬機(jī)中 將變量存儲(chǔ)到內(nèi)存從內(nèi)存中取出變量 這樣的底層細(xì)節(jié)抬闯。此處的變量(Variables)與 Java 變成中所說(shuō)的變量有所區(qū)別井辆,它包括了實(shí)例變量、靜態(tài)變量和構(gòu)成數(shù)組對(duì)象的元素溶握,但不包括局部變量與方法參數(shù)杯缺,因?yàn)楹笳呤蔷€(xiàn)程私有的,不會(huì)被共享睡榆,自然就不會(huì)存在競(jìng)爭(zhēng)問(wèn)題萍肆。

為了獲得較好的執(zhí)行效能,Java 內(nèi)存模型并沒(méi)有限制執(zhí)行引擎使用處理器的特定寄存器或緩存來(lái)和主內(nèi)存進(jìn)行交互胀屿,也沒(méi)有限制即時(shí)編譯器進(jìn)行調(diào)整代碼執(zhí)行順序這類(lèi)優(yōu)化措施塘揣。

二、主內(nèi)存與工作內(nèi)存

Java 內(nèi)存模型規(guī)定了所有的變量都存儲(chǔ)在主內(nèi)存(Main Memory碉纳, 這里指的是虛擬機(jī)內(nèi)存的一部分)中勿负。每條線(xiàn)程還有自己的工作內(nèi)存(Working Memory,可以與處理器高速緩存類(lèi)比),線(xiàn)程的工作內(nèi)存中保存了被該線(xiàn)程使用到的變量的主內(nèi)存副本拷貝奴愉,線(xiàn)程對(duì)變量的所有操作(讀取琅摩、賦值等)都必須在工作內(nèi)存中進(jìn)行,而不能直接讀寫(xiě)主內(nèi)存中的變量锭硼。

不同的線(xiàn)程之間也無(wú)法直接訪(fǎng)問(wèn)對(duì)方工作內(nèi)存中的變量房资,線(xiàn)程間變量值的傳遞均需要通過(guò)主內(nèi)存來(lái)完成,線(xiàn)程檀头、主內(nèi)存轰异、工作內(nèi)存三者的交互關(guān)系如下圖所示。
線(xiàn)程暑始、主內(nèi)存搭独、工作內(nèi)存三者的交互關(guān)系

這里說(shuō)的主內(nèi)存、工作內(nèi)存和 Java 內(nèi)存區(qū)域中的 Java 堆廊镜、棧牙肝、方法區(qū)等并不是同一個(gè)層次的內(nèi)存劃分,這兩者基本是沒(méi)有關(guān)系的嗤朴,如果兩者一定要勉強(qiáng)對(duì)應(yīng)起來(lái)的話(huà)配椭,那從變量、主內(nèi)存雹姊、工作內(nèi)存的定義來(lái)看股缸,主內(nèi)存主要對(duì)應(yīng)于 Java 堆中的對(duì)象實(shí)例數(shù)據(jù)部分,而工作內(nèi)存則對(duì)應(yīng)于 Java 虛擬機(jī)棧中的部分區(qū)域吱雏。

三敦姻、內(nèi)存件交互操作

關(guān)于 主內(nèi)存 和 工作內(nèi)存 之間具體的交互協(xié)議,即一個(gè)變量如何從主內(nèi)存拷貝到工作內(nèi)存歧杏、如何從工作內(nèi)存同步回主內(nèi)存之類(lèi)的實(shí)現(xiàn)細(xì)節(jié)替劈,Java 內(nèi)存模型中定義了一下 8 中操作來(lái)完成,虛擬機(jī)實(shí)現(xiàn)時(shí)必須保證下面提及的每一種操作都是原子的得滤、不可再分的(對(duì)于 double 和 long 類(lèi)型的變量來(lái)說(shuō),在某些平臺(tái)上允許有例外盒犹,這個(gè)問(wèn)題將在下文中說(shuō)明)懂更。

  • lock(鎖定):作用于主內(nèi)存的變量,它把一個(gè)變量標(biāo)識(shí)為一條線(xiàn)程獨(dú)占的狀態(tài)急膀。
  • unlock(解鎖):作用于主內(nèi)存的變量沮协,它把一個(gè)處于鎖定狀態(tài)的變量釋放出來(lái),釋放后變量才可以被其他線(xiàn)程鎖定卓嫂。
  • read(讀瓤对荨):作用于主內(nèi)存的變量,它把一個(gè)變量的值從主內(nèi)存?zhèn)鬏數(shù)焦ぷ鲀?nèi)存中,以便隨后的 load 動(dòng)作使用行瑞。
  • load(載入):作用于工作內(nèi)存的變量奸腺,它把 read 操作從主內(nèi)存得到的變量值保存到工作內(nèi)存的變量副本中。
  • use(使用):作用于工作內(nèi)存的變量血久,它把工作內(nèi)存中的一個(gè)變量的值傳遞給執(zhí)行引擎(一般是基于操作數(shù)棧的執(zhí)行引擎)突照,每當(dāng)虛擬機(jī)遇到一個(gè)需要使用到該變量的值的 字節(jié)碼指令時(shí)將會(huì)執(zhí)行這個(gè)操作。
  • assign(賦值):作用于工作內(nèi)存的變量氧吐,它把從執(zhí)行引擎接收到的值賦值給工作內(nèi)存的變量(存放在局部變量表中)讹蘑,每當(dāng)虛擬機(jī)遇到一個(gè)給變量賦值的字節(jié)碼指令時(shí)執(zhí)行這個(gè)操作。
  • store(存儲(chǔ)):作用于工作內(nèi)存的變量筑舅,它把工作內(nèi)存中的變量傳送到主內(nèi)存中座慰,以便隨后的 write 操作使用。
  • write(寫(xiě)入):作用于主內(nèi)存的變量翠拣,它把 store 操作從工作內(nèi)存中得到的變量的值方法主內(nèi)存的變量中版仔。

其中 read、load心剥、use邦尊、assign、store 和 write 這 6 種操作的關(guān)系如下圖所示优烧。
點(diǎn)擊看大圖

Java 內(nèi)存模型規(guī)定了在執(zhí)行上述 8 中基本操作時(shí)必須滿(mǎn)足如下規(guī)則:

  • 不允許 read 和 load蝉揍、store 和 write 操作之一單獨(dú)出現(xiàn),即不允許一個(gè)變量從主內(nèi)存讀取了但工作內(nèi)存不接受畦娄,或者工作內(nèi)存發(fā)起會(huì)回寫(xiě)了但主內(nèi)存不接受的情況出現(xiàn)又沾。
  • 不允許一個(gè)現(xiàn)場(chǎng)丟棄它的最近的 assign 操作,即變量的值在工作內(nèi)存改變了以后必須把該變化同步到主內(nèi)存中熙卡。
  • 不允許一個(gè)線(xiàn)程無(wú)原因的(沒(méi)有發(fā)生過(guò)任何 assing 操作)把數(shù)據(jù)從線(xiàn)程的工作內(nèi)存同步回主內(nèi)存中杖刷。
  • 一個(gè)新的變量只能在主內(nèi)存中“誕生”,不允許在工作內(nèi)存使用一個(gè)未被初始化(load 或 assing)的變量驳癌,換句話(huà)說(shuō)滑燃,就是對(duì)一個(gè)變量實(shí)施 use、store 操作之前颓鲜,必須先執(zhí)行過(guò) assign 和 load 操作表窘。
  • 一個(gè)變量在同一個(gè)時(shí)刻只允許一條線(xiàn)程對(duì)其進(jìn)行 lock 操作,但 lock 操作可以被同一線(xiàn)程重復(fù)執(zhí)行多次甜滨,多次執(zhí)行 lock 之后乐严,只有執(zhí)行相同次的 unlock 操作,變量才會(huì)被解鎖衣摩。
  • 如果對(duì)一個(gè)變量進(jìn)行 lock 操作昂验,那么將會(huì)清空工作內(nèi)存中這個(gè)變量的值,在執(zhí)行引擎使用這個(gè)變量前,需要重新執(zhí)行 load 或 assign 操作初始化變量的值既琴。
  • 如果一個(gè)變量事先沒(méi)有被 lock 操作鎖定占婉,那就不允許對(duì)它執(zhí)行 unlock 操作,也不允許去 unlock 一個(gè)被其他線(xiàn)程鎖定住的變量呛梆。
  • 對(duì)一個(gè)變量執(zhí)行 unlock 之前锐涯,必須先把此變量同步回主內(nèi)存中(執(zhí)行 store 以及 write 操作)。
    這 8 中內(nèi)存方法操作以及上述規(guī)則限定填物,再加上稍后 volatile 的一些特殊規(guī)定纹腌,就已經(jīng)完全確定了 Java 程序中哪些內(nèi)存訪(fǎng)問(wèn)操作在并發(fā)下是安全的。

四滞磺、對(duì)于 volatile 型變量的特殊規(guī)則

當(dāng)一個(gè)變量定義為 volatile 之后升薯,它將具備兩種特性:保證變量的可見(jiàn)性禁止指令重排序優(yōu)化

  • 第一個(gè)是保證此變量對(duì)所有線(xiàn)程的可見(jiàn)性击困,這里的“可見(jiàn)性”是指當(dāng)一條線(xiàn)程改變了這個(gè)變量的值涎劈,新值對(duì)于其他線(xiàn)程來(lái)說(shuō)是 立即得知 的。而普通變量做不到這一點(diǎn)阅茶,普通變量的值在線(xiàn)程間傳遞均需要通過(guò)主內(nèi)存來(lái)完成蛛枚,例如,線(xiàn)程 A 修改了一個(gè)普通變量的值脸哀,然后向主內(nèi)存進(jìn)行回寫(xiě)蹦浦,另外一個(gè)線(xiàn)程 B 在線(xiàn)程 A 回寫(xiě)完成了之后再?gòu)闹鲀?nèi)存進(jìn)行讀取操作,新變量才會(huì)對(duì)線(xiàn)程 B 可見(jiàn)撞蜂。
    關(guān)于 volatile 變量的可見(jiàn)性盲镶,寫(xiě)操作在并發(fā)下是安全的,但是 volatile 變量的運(yùn)算在并發(fā)下不是安全 的蝌诡,因?yàn)?Java 里面的運(yùn)算并非原子操作溉贿。
  • 使用 volatile 變量的第二個(gè)語(yǔ)義是禁止指令重排序優(yōu)化,普通的變量?jī)H僅會(huì)保證在該方法的執(zhí)行過(guò)程中所有依賴(lài)賦值結(jié)果的地方都能獲取到正確的結(jié)果浦旱,而不能保證變量賦值操作的順序與程序代碼中的執(zhí)行順序一致宇色。

了解了volatile 的語(yǔ)義問(wèn)題,那么我們來(lái)比較一下 使用 volatile 的代碼和使用其他的同步工具更快哪個(gè)更快颁湖?

  • 在某些情況下代兵,volatile 的同步機(jī)制的性能確實(shí)要優(yōu)于(使用 synchronized 關(guān)鍵字或 java.util.concurrent 包里面的鎖),但是由于虛擬機(jī)對(duì)鎖實(shí)行的許多消除和優(yōu)化爷狈,使得我們很難量化地認(rèn)為 volatile 就會(huì)比 synchronized 塊多少。如果讓 volatile 自己與普通變量比較:volatile 變量讀操作的性能消耗與普通變量幾乎沒(méi)有什么差別裳擎,但是寫(xiě)操作則可能會(huì)慢一些涎永,因?yàn)樗枰诒镜卮a中插入許多內(nèi)存屏障指令來(lái)保證處理器不發(fā)生亂序執(zhí)行。

最后看一下 Java 內(nèi)存模型對(duì) volatile 變量定義的特殊規(guī)則。假定 T 表示一個(gè)線(xiàn)程羡微, V 和 W 分別表示兩個(gè) volatile 型變量谷饿,那么在進(jìn)行 read、load妈倔、use博投、assign、store 和 write 操作時(shí)需要滿(mǎn)足如下規(guī)則:

  • 只有當(dāng)線(xiàn)程 T 對(duì)變量 V 執(zhí)行的前一個(gè)動(dòng)作是 load 的時(shí)候盯蝴,線(xiàn)程 T 才能對(duì)變量 V 執(zhí)行 use 動(dòng)作毅哗;并且,只有當(dāng)線(xiàn)程 T 對(duì)變量 V 執(zhí)行的后一個(gè)動(dòng)作是 use 的時(shí)候捧挺,線(xiàn)程 T 才能對(duì)變量 V 執(zhí)行 load 動(dòng)作虑绵。線(xiàn)程 T 對(duì)變量 V 的 use 動(dòng)作可以認(rèn)為是和線(xiàn)程 T 對(duì)變量 V 的 load、read 動(dòng)作相關(guān)聯(lián)闽烙,必須連續(xù)一起出現(xiàn)(這條規(guī)則要求在工作內(nèi)存中翅睛,每次使用 V 前都必須先沖主內(nèi)存刷新最新的值,用于保證能看見(jiàn)其他線(xiàn)程對(duì)變量 V 所做的修改后的值)黑竞。
  • 只有當(dāng)線(xiàn)程 T 對(duì)變量 V 執(zhí)行的前一個(gè)動(dòng)作是 assign 的時(shí)候捕发,線(xiàn)程 T 才能對(duì)變量 V 執(zhí)行 store 動(dòng)作;并且很魂,只有當(dāng)線(xiàn)程 T 對(duì)變量 V 執(zhí)行的后一個(gè)動(dòng)作是 store 的時(shí)候扎酷,線(xiàn)程 T 才能對(duì)變量 V 執(zhí)行 assign 動(dòng)作。線(xiàn)程 T 對(duì)變量 V 的 assign 動(dòng)作可以認(rèn)為是和線(xiàn)程 T 對(duì)變量 V 的 store莫换、write 動(dòng)作相關(guān)聯(lián)霞玄,必須連續(xù)一起出現(xiàn)(這條規(guī)則要求在工作內(nèi)存中,每次修改 V 后都必須立刻同步回主內(nèi)存中拉岁,用于保證其他線(xiàn)程可以看到自己對(duì)變量 V 所做的修改)坷剧。
  • 假定動(dòng)作 A 是線(xiàn)程 T 對(duì)變量 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)的對(duì)變量 V 的 read 或 write 動(dòng)作惫企;類(lèi)似的,假定動(dòng)作 B 是線(xiàn)程 T 對(duì)變量 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)的對(duì)變量 W 的 read 或 write 動(dòng)作。如果 A 先于 B巩掺,那么 P 先于 Q(這條規(guī)則要求 volatile 修飾的變量不會(huì)被指令重排序優(yōu)化偏序,保證代碼的執(zhí)行順序與程序相同)。

五胖替、對(duì)于 long 和 double 型變量的特殊規(guī)則

Java 內(nèi)存模型要求 lock研儒、unlock豫缨、read、load端朵、use好芭、assign、store冲呢、write 這 8 個(gè)操作都具有原子性舍败,但是對(duì)于 64 位的數(shù)據(jù)類(lèi)型(long 和 double),在模型中特別定義了一條相對(duì)寬松的規(guī)定:允許虛擬機(jī)將沒(méi)有被 volatile 修飾的 64 位數(shù)據(jù)的讀寫(xiě)操作劃分為兩次 32 位的操作來(lái)進(jìn)行敬拓,即允許虛擬機(jī)實(shí)現(xiàn)選擇可以不保證 64 位數(shù)據(jù)類(lèi)型的 load邻薯、store、read 和 write 這 4 個(gè)操作的原子性恩尾。

不過(guò)弛说,在實(shí)際開(kāi)發(fā)中,目前各種平臺(tái)下的商用虛擬機(jī)幾乎都選擇把 64 位的數(shù)據(jù)的讀寫(xiě)操作作為院子操作來(lái)對(duì)待翰意,因此我們?cè)诰帉?xiě)代碼時(shí)一般不需要把用到的 long 和 double 變量專(zhuān)門(mén)聲明為 volatile木人。

六、原子性冀偶、可見(jiàn)性與有序性

Java 內(nèi)存模型是圍繞著在并發(fā)過(guò)程中如何處理原子性醒第、可見(jiàn)性和有序性這 3 個(gè)特征來(lái)建立的。

  • 原子性(Atomicity):由 Java 內(nèi)存模型來(lái)直接保證的原子性變量操作包括 read进鸠、load稠曼、use、assign客年、store 和 write霞幅,我們大致可以認(rèn)為 基本數(shù)據(jù)類(lèi)型 的訪(fǎng)問(wèn)讀寫(xiě)是具備原子性的(例外就是 long 和 double 的非原子協(xié)定)。
    如果應(yīng)用場(chǎng)景需要一個(gè)更大范圍(包括基本數(shù)據(jù)類(lèi)型以外的變量)的原子性保證量瓜,Java 內(nèi)存模型還提供了 lock 和 unlock 操作來(lái)滿(mǎn)足這種需求司恳,盡管虛擬機(jī)未把 lock 和 unlock 操作直接開(kāi)發(fā)給用戶(hù)使用,但是卻提供了更高層次的字節(jié)碼指令 monitorenter 和 monitorexit 來(lái)隱式地使用這兩個(gè)操作绍傲,這兩字節(jié)碼指令反映到 Java 代碼中就是同步塊——synchronized 關(guān)鍵字扔傅,因此在 synchronized 塊之間的操作也具備原子性。
    也就是說(shuō) Java 內(nèi)存模型中的 read烫饼、load猎塞、use、assign杠纵、store 和 wriet 這 6 種操作可以保證 基本數(shù)據(jù)類(lèi)型 的原子性荠耽,而 Java 內(nèi)存模型定義的 lock 和 unlock 操作則可以保證 基本數(shù)據(jù)類(lèi)型 以外的數(shù)據(jù)類(lèi)型的原子性
  • 可見(jiàn)性(Visibility):可見(jiàn)性是指一個(gè)線(xiàn)程修改了一個(gè)變量的值比藻,其他線(xiàn)程可以立即得知這個(gè)修改铝量。Java 內(nèi)存模型是通過(guò)在工作內(nèi)存中變量修改后將新值立即同步回主內(nèi)存伊履,在工作內(nèi)存中變量讀取前從主內(nèi)存刷新新變量的值這種依賴(lài)主內(nèi)存作為傳遞媒介的方式來(lái)實(shí)現(xiàn)可見(jiàn)性的。無(wú)論是普通變量還是 volatile 變量都是如此款违,普通變量與 volatile 變量的區(qū)別是,volatile 的特殊規(guī)則保證了新值能立即同步到主內(nèi)存群凶,以及每次使用前立即從主內(nèi)存刷新插爹。因此,可以說(shuō) volatile 保證了多線(xiàn)程操作時(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)存中此變量的值同步回主內(nèi)存中(執(zhí)行 store够坐、write 操作)”這條規(guī)則獲得的寸宵,而 final關(guān)鍵字的可見(jiàn)性是指:被 final 修飾的字段在構(gòu)造器中一旦初始化完成,并且構(gòu)造器沒(méi)有把 “this” 引用傳遞出去元咙,那在其他線(xiàn)程中就能看見(jiàn) final 字段的值梯影。
  • 有序性(Ordering):Java 程序中天然的有序性可以總結(jié)為一句話(huà):如果在本線(xiàn)程內(nèi)觀察,所有的操作都是有序的庶香;如果在一個(gè)線(xiàn)程中觀察另一個(gè)線(xiàn)程甲棍,所有的操作都是無(wú)序的。前半句是指“線(xiàn)程內(nèi)表現(xiàn)為串行的語(yǔ)義”赶掖,后半句是指“指令重排序”現(xiàn)象和“工作內(nèi)存與主內(nèi)存同步延遲”現(xiàn)象感猛。
    Java 語(yǔ)言提供了 volatile 和 synchronized 兩個(gè)關(guān)鍵字來(lái)保證線(xiàn)程之間操作的有序性,volatile 關(guān)鍵字本身就包含了進(jìn)制指令重排序的語(yǔ)義奢赂,而 synchronized 則是由“一個(gè)變量在同一個(gè)時(shí)刻只允許一條線(xiàn)程對(duì)其進(jìn)行 lock 操作”這條規(guī)則獲得的陪白,這條規(guī)則決定了持有同一個(gè)鎖的兩個(gè)同步塊只能串行的進(jìn)入。

介紹完并發(fā)中 3 中重要的特性后呈驶,有沒(méi)有發(fā)現(xiàn) synchronized 關(guān)鍵字在需要 3 中特性的時(shí)候都可以作為其中一種的解決方案拷泽。

七、先行發(fā)生原則

如果 Java 內(nèi)存模型中所有的有序性都僅僅靠 volatile 和 synchronized 來(lái)完成袖瞻,那么有一些操作將會(huì)變得很煩瑣司致,但是我們?cè)诰帉?xiě) Java 并發(fā)代碼的時(shí)候并沒(méi)有感覺(jué)到這一點(diǎn),這是因?yàn)?Java 語(yǔ)言中有一個(gè) “先行發(fā)生”(happens-before)的原則聋迎。這個(gè)原則非常重要脂矫,它是判斷數(shù)據(jù)是否存在競(jìng)爭(zhēng)、線(xiàn)程是否安全的主要依據(jù)霉晕,依靠這個(gè)原則庭再,我們可以通過(guò)幾條規(guī)則一攬子地解決并發(fā)環(huán)境下兩個(gè)操作之間是否可能存在沖突的所有問(wèn)題捞奕。

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

  • 程序次序規(guī)則:在一個(gè)線(xiàn)程內(nèi)斧抱,按照程序代碼順序常拓,書(shū)寫(xiě)在前面的操作先行發(fā)生于書(shū)寫(xiě)在后面的操作。準(zhǔn)備的說(shuō)辉浦,應(yīng)該是控制流順序而不是程序代碼順序弄抬,因?yàn)橐紤]分支、循環(huán)等結(jié)構(gòu)宪郊。
  • 管程鎖定規(guī)則:一個(gè) unlock 操作先行發(fā)生于后面對(duì)同一個(gè)鎖的 lock 操作掂恕。這里必須強(qiáng)調(diào)的是同一個(gè)鎖,而“后面”是指時(shí)間上的先后順序废膘。
  • volatile 變量規(guī)則:對(duì)一個(gè) volatile 變量的寫(xiě)操作先行發(fā)生于后面對(duì)這個(gè)變量的讀操作竹海,這里的“后面”同樣是指時(shí)間上的先后順序。
  • 線(xiàn)程啟動(dòng)規(guī)則:Thread 對(duì)象的 start() 方法先行發(fā)生于此線(xiàn)程的每一個(gè)動(dòng)作丐黄。
  • 線(xiàn)程終止規(guī)則:線(xiàn)程中的所有操作都先行于對(duì)此線(xiàn)程的終止檢測(cè)斋配,我們可以通過(guò) Thread.join() 方法結(jié)束、Thead.isAlive() 的返回值等手段檢測(cè)到線(xiàn)程已經(jīng)終止執(zhí)行灌闺。
  • 線(xiàn)程中斷規(guī)則:對(duì)線(xiàn)程 interrupt() 方法的調(diào)用先行發(fā)生于被中斷線(xiàn)程的代碼檢測(cè)到中斷事件的發(fā)生艰争,可以通過(guò) Thread.interrupted() 方法檢測(cè)到是否有中斷發(fā)生。
  • 對(duì)象終結(jié)規(guī)則:一個(gè)對(duì)象的初始化完成(構(gòu)造函數(shù)執(zhí)行結(jié)束)先行于發(fā)生于它的 finalized() 方法的開(kāi)始桂对。
  • 傳遞性:如果操作 A 先行發(fā)生于操作 B甩卓,操作 B 先行發(fā)生于操作 C,那就可以得出操作 A 先行發(fā)生于操作 C 的結(jié)論蕉斜。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末逾柿,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子宅此,更是在濱河造成了極大的恐慌机错,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,386評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件父腕,死亡現(xiàn)場(chǎng)離奇詭異弱匪,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)璧亮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)萧诫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)斥难,“玉大人,你說(shuō)我怎么就攤上這事帘饶⊙普铮” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,704評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵及刻,是天一觀的道長(zhǎng)搭儒。 經(jīng)常有香客問(wèn)我,道長(zhǎng)提茁,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,702評(píng)論 1 294
  • 正文 為了忘掉前任馁菜,我火速辦了婚禮茴扁,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘汪疮。我一直安慰自己峭火,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布智嚷。 她就那樣靜靜地躺著卖丸,像睡著了一般。 火紅的嫁衣襯著肌膚如雪盏道。 梳的紋絲不亂的頭發(fā)上稍浆,一...
    開(kāi)封第一講書(shū)人閱讀 51,573評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音猜嘱,去河邊找鬼衅枫。 笑死,一個(gè)胖子當(dāng)著我的面吹牛朗伶,可吹牛的內(nèi)容都是我干的弦撩。 我是一名探鬼主播,決...
    沈念sama閱讀 40,314評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼论皆,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼益楼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起点晴,我...
    開(kāi)封第一講書(shū)人閱讀 39,230評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤感凤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后觉鼻,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體俊扭,經(jīng)...
    沈念sama閱讀 45,680評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評(píng)論 3 336
  • 正文 我和宋清朗相戀三年坠陈,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了萨惑。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片捐康。...
    茶點(diǎn)故事閱讀 39,991評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖庸蔼,靈堂內(nèi)的尸體忽然破棺而出解总,到底是詐尸還是另有隱情,我是刑警寧澤姐仅,帶...
    沈念sama閱讀 35,706評(píng)論 5 346
  • 正文 年R本政府宣布花枫,位于F島的核電站,受9級(jí)特大地震影響掏膏,放射性物質(zhì)發(fā)生泄漏劳翰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評(píng)論 3 330
  • 文/蒙蒙 一馒疹、第九天 我趴在偏房一處隱蔽的房頂上張望佳簸。 院中可真熱鬧,春花似錦颖变、人聲如沸生均。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,910評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)马胧。三九已至,卻和暖如春衔峰,著一層夾襖步出監(jiān)牢的瞬間佩脊,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,038評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工垫卤, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留邻吞,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,158評(píng)論 3 370
  • 正文 我出身青樓葫男,卻偏偏與公主長(zhǎng)得像抱冷,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子梢褐,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容