簡體   English   中英

關於可見性的Java並發問題

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM