原子性
原子性是指一個(gè)操作是不可中斷的。即使是在多個(gè)線程一起執(zhí)行的時(shí)候,一個(gè)操作一旦開(kāi)始,就不會(huì)被其它線程干擾。
由 Java 內(nèi)存模型直接保證的原子性變量操作包括 read、load、assign、use、store 和 write,我們大致可以認(rèn)為基本數(shù)據(jù)類型的訪問(wèn)讀寫(xiě)是具備原子性的(例外就是 long 和 double 的非原子性協(xié)定)。
盡管虛擬機(jī)未把 lock 和 unlock 操作直接開(kāi)放給用戶使用,但是卻提供了更高層次的字節(jié)碼指令monitorenter 和 monitorexit 來(lái)隱式地使用這兩個(gè)操作,這兩個(gè)字節(jié)碼指令反映到 Java 代碼中就是同步塊——synchronized 關(guān)鍵字,因此在 synchronized 塊之間的操作也具備原子性。
可見(jiàn)性
可見(jiàn)性(Visibility):可見(jiàn)性是指當(dāng)一個(gè)線程修改了共享變量的值,其他線程能夠立即得知這個(gè)修改。
除了 volatile 以外,Java 還有兩個(gè)關(guān)鍵字能實(shí)現(xiàn)可見(jiàn)性,即 synchronized 和 final。
- 同步塊的可見(jiàn)性是由「對(duì)一個(gè)變量執(zhí)行 unlock 操作之前,必須先把此變量同步回主內(nèi)存中(執(zhí)行 store、write 操作)」這條規(guī)則獲得的,
- final 關(guān)鍵字的可見(jiàn)性是指:保證一個(gè)對(duì)象的構(gòu)建方法結(jié)束前,所有 final 成員變量都必須完成初始化(前提是沒(méi)有 this 引用溢出)。在構(gòu)造器中一旦初始化完成,并且構(gòu)造器沒(méi)有把「this」的引用傳遞出去,那在其他線程中就能看見(jiàn) final 字段的值。
-
this 引用逃逸 是指在構(gòu)造函數(shù)返回之前其他線程就持有該對(duì)象的引用。調(diào)用尚未構(gòu)造完全的對(duì)象的方法可能引發(fā)令人疑惑的錯(cuò)誤, 因此應(yīng)該避免 this 逃逸的發(fā)生。
- 例子:在構(gòu)造函數(shù)中啟動(dòng)線程 / 注冊(cè)監(jiān)聽(tīng)器/ 創(chuàng)建匿名內(nèi)部類。
-
this 引用逃逸 是指在構(gòu)造函數(shù)返回之前其他線程就持有該對(duì)象的引用。調(diào)用尚未構(gòu)造完全的對(duì)象的方法可能引發(fā)令人疑惑的錯(cuò)誤, 因此應(yīng)該避免 this 逃逸的發(fā)生。
有序性
如果在本線程內(nèi)觀察,所有的操作都是有序的;如果在一個(gè)線程中觀察另一個(gè)線程,所有的操作都是無(wú)序的。前半句是指「線程內(nèi)表現(xiàn)為串行的語(yǔ)義」(Within-Thread As-If-Serial Semantics),后半句是指「指令重排序」現(xiàn)象和「工作內(nèi)存與主內(nèi)存同步延遲」現(xiàn)象。