[英]Java concurrency issue about visibility
我讀到synchronized
方法或塊提供了兩個功能:“互斥”和“可見性”。 我想知道兩件事。
public class A{
private final Object lock = new Object();
private C obj = new C();
public void methodA(){
synchronized(lock){
obj.x = 1;
obj.y=3;
}
}
public void methodB(C obj2){
synchronized(lock){
obj2.x = obj.x;
}
}
}
讓我們假設我們有2個線程調用methodA
類型的全局共享對象上A
,而lock
被收購thread1
,現在經過thread1
解除lock
。 現在可見性是所有其他線程都會讀取對obj
的更改? 即, synchronized
塊內的每個變化都可見? 或者我應該將C對象更改為volatile
以使其對其他人可見?
使obj
volatile
將使C對象的引用變為volatile
。 即在同步塊外可見。 它不會影響該對象的成員。
即對另一個線程可以看到對obj的重新分配。 重新分配給其成員不會。
在synchronized塊內部的每一個變化都是可見的嗎?
是的,這是個主意。 JLS 17.45定義發生在關系之前。 尤其是:
監視器上的解鎖發生在該監視器上的每個后續鎖定之前。
因此,當thread2獲取鎖時,您可以保證在保持同一個鎖時它將看到thread1所做的更改。
我應該將C對象更改為volatile以使其對其他人可見嗎?
volatile保證如果你寫: obj = new C();
在某個地方,隨后讀取obj
會看到它現在指的是一個新對象。 但是,它沒有對obj的“內容”提供任何此類保證。 所以如果你寫: obj.x = someValue;
,如果obj是易變的,那么您無法保證更改對另一個線程可見。 除非你讓x
易變。
現在可見性是所有其他線程都會讀取對obj的更改?
只有該鎖定的同步塊內的線程。
在synchronized塊內部的每一個變化都是可見的嗎?
只是可能。 對於保證可見性,線程必須位於同步塊內。
或者我應該將C對象更改為volatile?
如果你沒有同步並且在這里沒有任何區別,那將無濟於事。 volatile
只會改變obj
引用的行為,而不是它的字段。
不,訪問obj
字段仍然不是線程安全的。 鎖對象上的同步僅允許您通過線程安全操作將值寫入此塊中的obj
字段。
UPD :對obj
volatile
不會幫助你,因為你不會改變這個字段自己的參考值。
要回答你的問題,另一種方法可以簡單地讓你訪問變量obj,也沒有鎖。 您必須確保的是,必須通過鎖定小心地保護對obj的所有訪問,以便obj不處於不一致狀態(由程序員定義)。
在您的特定示例中,它看起來足夠一致。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.