5 回答

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

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

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

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

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