亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Java中同步的可見性影響

Java中同步的可見性影響

智慧大石 2021-11-17 15:29:59
這篇文章說:在這個不合規的代碼示例中,Helper 類通過將其字段聲明為 final 使其不可變。JMM 保證不可變對象在它們對任何其他線程可見之前被完全構造。getHelper() 方法中的塊同步保證所有可以看到 helper 字段的非空值的線程也將看到完全初始化的 Helper 對象。public final class Helper {  private final int n;  public Helper(int n) {    this.n = n;  }  // Other fields and methods, all fields are final}final class Foo {  private Helper helper = null;  public Helper getHelper() {    if (helper == null) {            // First read of helper      synchronized (this) {        if (helper == null) {        // Second read of helper          helper = new Helper(42);        }      }    }    return helper;                   // Third read of helper  }}但是,此代碼不能保證在所有 Java 虛擬機平臺上都能成功,因為在 helper 的第一次讀取和第三次讀取之間沒有發生之前的關系。因此,第三次讀取 helper 有可能獲得一個陳舊的空值(可能是因為它的值被編譯器緩存或重新排序),導致 getHelper() 方法返回一個空指針。我不知道該怎么辦。我同意一讀和三讀之間沒有發生之前的關系,至少沒有直接的關系。從某種意義上說,第一次讀取必須在第二次之前發生,第二次讀取必須在第三次之前發生,因此第一次讀取必須在第三次之前發生時,是否存在傳遞性發生在之前的關系?有人能更專業地闡述嗎?
查看完整描述

3 回答

?
慕尼黑5688855

TA貢獻1848條經驗 獲得超2個贊

不,沒有傳遞關系。


JMM 背后的想法是定義 JVM 必須遵守的規則。如果 JVM 遵循這些規則,它們就有權根據需要重新排序和執行代碼。


在您的示例中,第 2 次讀取和第 3 次讀取不相關 -例如使用synchronized或不會引入內存障礙volatile。因此,JVM 可以按如下方式執行它:


 public Helper getHelper() {

    final Helper toReturn = helper;  // "3rd" read, reading null

    if (helper == null) {            // First read of helper

      synchronized (this) {

        if (helper == null) {        // Second read of helper

          helper = new Helper(42);

        }

      }

    }


    return toReturn; // Returning null

  }

然后您的調用將返回一個空值。然而,會創建一個單例值。但是,后續調用可能仍會獲得空值。


正如所建議的,使用 volatile 會引入新的內存屏障。另一種常見的解決方案是捕獲讀取的值并返回它。


 public Helper getHelper() {

    Helper singleton = helper;

    if (singleton == null) {

      synchronized (this) {

        singleton = helper;

        if (singleton == null) {

          singleton = new Helper(42);

          helper = singleton;

        }

      }

    }


    return singleton;

  }

由于您依賴于局部變量,因此無需重新排序。一切都發生在同一個線程中。


查看完整回答
反對 回復 2021-11-17
?
www說

TA貢獻1775條經驗 獲得超8個贊

不,這些讀取之間沒有任何傳遞關系。synchornized只保證在同一個鎖的同步塊內所做的更改的可見性。在這種情況下,所有讀取都不會使用同一個鎖上的同步塊,因此這是有缺陷的并且不保證可見性。


因為一旦字段被初始化就沒有鎖定,所以聲明該字段是至關重要的volatile。這將確??梢娦?。


private volatile Helper helper = null;


查看完整回答
反對 回復 2021-11-17
?
小怪獸愛吃肉

TA貢獻1852條經驗 獲得超1個贊

這一切都在這里解釋https://shipilev.net/blog/2014/safe-public-construction/#_singletons_and_singleton_factories,問題很簡單。

... 請注意,我們在此代碼中對實例進行了多次讀取,并且至少“讀取 1”和“讀取 3”是沒有任何同步的讀取...規范方面,如發生在一致性規則中所述,讀取操作可以通過競態觀察無序寫入。這是為每個讀取操作決定的,無論其他哪些操作已經讀取了相同的位置。在我們的例子中,這意味著即使“read 1”可以讀取非空實例,代碼然后繼續返回它,然后它進行另一個活潑的讀取,它可以讀取一個空實例,它將被返回!


查看完整回答
反對 回復 2021-11-17
  • 3 回答
  • 0 關注
  • 228 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號