5 回答

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

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

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

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

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