為什么雙重檢驗(yàn)?zāi)J叫枰由蟰olatile關(guān)鍵字

如果不加volatile關(guān)鍵字的單例模式寫法如下:

public static Singleton getSingleton() {
  if (instance ==null) {//Single Checked
    synchronized (Singleton.class) {
      if (instance ==null) {//Double Checked
        instance =new Singleton();
      }
    }
  }
  return instance;
}

這段代碼看起來(lái)很完美,很可惜,它是有問(wèn)題。主要在于instance = new Singleton()這句,這并非是一個(gè)原子操作,事實(shí)上在 JVM 中這句話大概做了下面 3 件事情。

1、給 instance 分配內(nèi)存
2、調(diào)用 Singleton 的構(gòu)造函數(shù)來(lái)初始化成員變量
3、將instance對(duì)象指向分配的內(nèi)存空間(執(zhí)行完這步 instance 就為非 null 了)

但是在 JVM 的即時(shí)編譯器中存在指令重排序的優(yōu)化。也就是說(shuō)上面的第二步和第三步的順序是不能保證的,最終的執(zhí)行順序可能是 1-2-3 也可能是 1-3-2。如果是后者,則在 3 執(zhí)行完畢、2 未執(zhí)行之前,被線程二搶占了,這時(shí) instance 已經(jīng)是非 null 了(但卻沒(méi)有初始化),所以線程二會(huì)直接返回 instance,然后使用,然后順理成章地報(bào)錯(cuò)。

所以需要加上volatile關(guān)鍵字,禁止指令重排序,也就是將對(duì)象初始化之后,再將instance指向分配對(duì)象的內(nèi)存空間。

public class Singleton {
  private volatile static Singleton instance;//聲明成 volatile

  private Singleton (){}

  public static Singleton getSingleton() {
    if (instance ==null) {
      synchronized (Singleton.class) {
        if (instance ==null) {
          instance =new Singleton();
        }
      }
    }
    return instance;
  }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容