1. 程式人生 > >對Java單例模式 volatile關鍵字作用的理解

對Java單例模式 volatile關鍵字作用的理解

初始 urn class .com 重新 on() 內存空間 sta 兩個

  單例模式是程序設計中經常用到的,簡單便捷的設計模式,也是很多程序猿對設計模式入門的第一節課。其中最經典的一種寫法是:

class Singleton {
    private volatile static Singleton instance;//volatile關鍵字防止指令重排
    private Singleton(){}
    public static Singleton getInstance() {
        if ( instance == null ) { //一重判斷
            synchronized (Singleton.class) {//對Singleton.class上鎖
                if ( instance == null ) {//二重判斷
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

  其中有兩個關鍵的地方:1,初始化instance實例的適合,采用兩重判斷對Singleton.class上鎖。

             2,靜態變量instance使用了volatile關鍵字進行修飾。

  第一個問題相對比較好理解  

        if ( instance == null ) { //一重判斷
            synchronized (Singleton.class) {//對Singleton.class上鎖
                if ( instance == null ) {//二重判斷
                    instance = new Singleton();
                }
            }
        }

  

  sychronized關鍵字鎖住Singleton類而不是instance對象,是因為,此時instance為空,加sychronized沒有意義。
第一重判斷的意義在於:如果instance非空,就跳過了鎖的步驟,減少加鎖的資源開銷。但是由於第一重判斷在代碼鎖之外,如果不同線程同時訪問到install==null,會先後阻塞執行代碼鎖內的內容。所以在代碼鎖內加第二重判斷就很有必要了,避免第一個線程獲取實例後,第二個線程獲得資源鎖又執行了一次instance的初始化,產生兩個不同的實例。

  很多人不理解instance實例在聲明時加volatile關鍵字的作用,或者是發現別人這麽寫了,自己也跟著這麽寫。對volatile關鍵字的解釋,很多地方只是提了句“當要求使用volatile 聲明的變量的值的時候,系統總是重新從它所在的內存讀取數據,它可以防止指令重排”,這裏不想對這句話進行展開解釋,想詳細了解可以參考文章
  https://www.cnblogs.com/shan1393/p/8999683.html


  https://www.cnblogs.com/xrq730/p/7048693.html

  instance = new Singleton()看上去只有一句話,但java的初始化成員變量包括內存分配、初始化、返回對象在堆上的引用等一系列操作。對於synchronized代碼塊內,一條語句完整執行是沒有問題的。但如果發生了指令重排,先返回對象在堆上的引用,再進行初始化。對於另一個執行到一重判斷的線程來說,由於instance已經指向了堆上的一段內存空間,那麽instance就不為空,會將未完成初始化的對象返回給其他函數調用,引發一系列不安全隱患。加了volatile關鍵字,可以保證返回對象在對上的引用發生在初始化之後,避免了這種情況的發生。這就是單例模式下 instance加volatile關鍵字的作用。

對Java單例模式 volatile關鍵字作用的理解