5 回答

TA貢獻(xiàn)1842條經(jīng)驗(yàn) 獲得超13個(gè)贊
同步可以防止垃圾收集,但一般情況下不會(huì)。對(duì)于您的具體情況,我們無法保證。
與JLS §12.6.1比較
…
這種類型的轉(zhuǎn)換可能會(huì)導(dǎo)致該
finalize
方法的調(diào)用比預(yù)期的更早發(fā)生。為了允許用戶防止這種情況,我們強(qiáng)制執(zhí)行同步可以使對(duì)象保持活動(dòng)狀態(tài)的概念。如果一個(gè)對(duì)象的終結(jié)器可以導(dǎo)致該對(duì)象上的同步,那么只要對(duì)該對(duì)象持有鎖,該對(duì)象就必須處于活動(dòng)狀態(tài)并且被認(rèn)為是可訪問的。請(qǐng)注意,這不會(huì)阻止同步消除:同步僅在終結(jié)器可能對(duì)其進(jìn)行同步時(shí)才使對(duì)象保持活動(dòng)狀態(tài)。由于終結(jié)器發(fā)生在另一個(gè)線程中,因此在許多情況下無論如何都無法刪除同步。
因此,由于您的對(duì)象沒有自定義終結(jié)器,因此在終結(jié)過程中可能不會(huì)發(fā)生同步,原則上,您的對(duì)象是一個(gè)允許消除鎖的臨時(shí)對(duì)象,在這種情況下,它不會(huì)阻止垃圾收集。
但是存在一個(gè)實(shí)際障礙,即您存儲(chǔ) a 的WeakReference
方式使得另一個(gè)線程可以在未收集該對(duì)象時(shí)檢索該對(duì)象,一旦存在這種可能性,該對(duì)象就不再是本地的,并且無法應(yīng)用鎖消除。
在構(gòu)造后立即積極收集對(duì)象(或完全消除其存在)并在其逃逸或WeakReference
首先創(chuàng)建空對(duì)象之前清除弱引用的理論實(shí)現(xiàn)將符合規(guī)范,就像在該執(zhí)行場景中一樣,鎖消除是有道理的。
請(qǐng)注意,即使您插入 a ,線程調(diào)用和另一個(gè)調(diào)用reachabilityFence
之間也沒有發(fā)生之前關(guān)系,因此第二個(gè)線程可能始終表現(xiàn)得好像在另一個(gè)線程完成塊或通過可達(dá)性柵欄之后執(zhí)行,即使您的真實(shí)線程生命時(shí)鐘卻另有說明。明確表示沒有同步語義。thread1()
thread2()
thread2()
synchronized
Thread.sleep

TA貢獻(xiàn)1802條經(jīng)驗(yàn) 獲得超5個(gè)贊
為了讓synchronized
塊的末尾刪除監(jiān)視器鎖,該synchronized
塊必須保留對(duì)返回的對(duì)象的引用getMonitorObject()
。
該引用會(huì)阻止 GC,所以答案是肯定的。

TA貢獻(xiàn)1806條經(jīng)驗(yàn) 獲得超8個(gè)贊
在我詳細(xì)研究過的所有 Java 實(shí)現(xiàn)中,對(duì)象的原始互斥體或鎖的狀態(tài)在第1部分中由對(duì)象頭中的位表示。當(dāng)鎖被釋放時(shí),JVM 需要更新標(biāo)頭位2,因此它仍然必須擁有對(duì)該對(duì)象的引用,無論是在堆棧上還是在寄存器中。
1 - 當(dāng)發(fā)生互斥鎖爭用時(shí),鎖會(huì)“膨脹”以記錄額外信息。所以我們不能說整個(gè)狀態(tài)都在對(duì)象頭中。
2 - 在大多數(shù)情況下,解鎖代碼不知道鎖定對(duì)象是否不可訪問。但如果它是由于積極的 JIT 編譯器優(yōu)化而實(shí)現(xiàn)的,那么假設(shè)它也可以知道不再需要更新對(duì)象頭。
但是假設(shè)解鎖互斥體時(shí)未使用/不需要對(duì)象引用。
以下是JLS 12.6.1中可達(dá)性的定義:
“可到達(dá)的對(duì)象是可以在任何潛在的持續(xù)計(jì)算中從任何活動(dòng)線程訪問的任何對(duì)象。”?“可以通過某些引用鏈從某些可終結(jié)的對(duì)象到達(dá)終結(jié)器可到達(dá)的對(duì)象,但不能從任何活動(dòng)線程到達(dá)?!?/em>
“任何一種方法都無法到達(dá)無法到達(dá)的對(duì)象。”
為了使對(duì)象成為垃圾收集的候選對(duì)象,它必須不可訪問。換句話說,它不能從任何活動(dòng)線程訪問。
鎖定的互斥鎖怎么樣?好吧,線程的“潛在的持續(xù)計(jì)算”可能需要解鎖互斥鎖:
如果互斥鎖在沒有對(duì)象引用的情況下無法解鎖,則該對(duì)象是可達(dá)的。
如果可以在不引用對(duì)象的情況下解鎖互斥鎖,那么該鎖可能無法訪問,或者終結(jié)器可訪問。
可是等等 ...
在JLS 12.6.2中,有一些關(guān)于可達(dá)性決策點(diǎn)的復(fù)雜語言。
“在每個(gè)可達(dá)性決策點(diǎn),某些對(duì)象集被標(biāo)記為不可達(dá),而這些對(duì)象的某些子集被標(biāo)記為可終結(jié)。”
" 如果對(duì)象 X 在 di 處被標(biāo)記為不可訪問,則: - ... - 在 di 之后的線程 t 中對(duì) X 的所有主動(dòng)使用都必須發(fā)生在 X 的終結(jié)器調(diào)用中,或者作為線程 t 執(zhí)行讀取的結(jié)果出現(xiàn)在對(duì) X 的引用的 di 之后;并且 - ...”
“當(dāng)且僅當(dāng)以下至少一項(xiàng)為真時(shí),操作
a
才是主動(dòng)使用: - ... -?鎖定或解鎖?,并且?在調(diào)用終結(jié)器之后發(fā)生鎖定操作. - .. ”。X
a
X
X
X
現(xiàn)在,如果我理解正確的話,那就是說,如果活動(dòng)線程仍然可以釋放相應(yīng)的互斥鎖,那么可終結(jié)的對(duì)象就無法被終結(jié)。
總之:
在當(dāng)前的 JVM 中,互斥鎖的鎖定狀態(tài)取決于對(duì)象頭。如果互斥體仍然可以被線程釋放,那么該對(duì)象必須是可訪問的......作為實(shí)現(xiàn)細(xì)節(jié)。
假設(shè)存在一個(gè) JVM,其中可以在不引用對(duì)象的情況下釋放互斥鎖,那么當(dāng)對(duì)象仍處于鎖定狀態(tài)時(shí),該對(duì)象可能無法訪問。
但是,如果該對(duì)象是可終結(jié)的,那么直到所有可能需要釋放鎖的活動(dòng)(應(yīng)用程序)線程都完成了該操作之后,該對(duì)象才會(huì)被終結(jié)。

TA貢獻(xiàn)1906條經(jīng)驗(yàn) 獲得超3個(gè)贊
我剛剛在javadoc中看到了這樣的“旁白”:
reachabilityFence
“在本身確??稍L問性的構(gòu)造中不需要[方法]。例如,因?yàn)橥ǔo法回收鎖定的對(duì)象,所以如果在類 Resource 的所有方法(包括Finalize)被包含在同步(this)塊中?!?/p>
這似乎是說,被鎖定的對(duì)象不能被垃圾收集。
我不確定這是否優(yōu)先于 JLS 12.6.1 和 12.6.2;請(qǐng)參閱我的其他答案,或者我們是否應(yīng)該將其理解為僅適用于 Oracle / OpenJDK Java 類庫的 Java(語言)實(shí)現(xiàn)。

TA貢獻(xiàn)1856條經(jīng)驗(yàn) 獲得超5個(gè)贊
sleep 方法不會(huì)離開同步塊,因此不會(huì)釋放鎖或監(jiān)視器對(duì)象,它只是阻塞執(zhí)行一段時(shí)間。由于鎖從未被釋放,垃圾收集器不會(huì)收集它,除非持有它的線程完成同步塊的執(zhí)行或使用wait()
方法釋放它。
所以,是的,如果有足夠的時(shí)間完成thread2()
調(diào)用,它保證不為空。thread1()
getMonitorObject()
添加回答
舉報(bào)