深入談談Java最簡單的單例設計模式

來源:互聯網
上載者:User

標籤:環境   多線程   就會   餓漢   instance   啟動   需要   網上   增加   

  單例設計模式是23種設計模式裡面最簡單的,但是要徹底理解單例,還是需要下一點功夫的。

單例一般會分為餓漢模式和懶漢模式

 餓漢模式:

1 public class Singleton2 {3     private static Singleton singleton = new Singleton();4 5     public static Singleton getInstance()6     {7         return singleton;8     }9 }

但是在一些系統應用環境中,這個單例對象可能比較大,在類載入的時候就初始化對象會增加系統啟動壓力,還會對系統資源造成浪費。所以就有了懶漢模式,只有在第一次調用的時候才創界對象執行個體。

懶漢模式:

 1 public class Singleton 2 { 3     private static Singleton singleton; 4  5     public static Singleton getInstance() 6     { 7         if (singleton == null) 8         { 9             singleton = new Singleton();10         }11         return singleton;12     }13 }

但是在多線程的環境中,以上內容就會有問題了。由於沒有同步,不同的線程可能同時進入if語句,然後分別建立了兩個執行個體,這時候Singleton就不再是單列了。

於是就有了雙重空判斷版本

public class Singleton{    private static Singleton1 singleton;    public static Singleton1 getInstance()    {        if (singleton == null)        {            synchronized (Singleton1.class)            {                if (singleton == null)                    singleton = new Singleton();            }        }        return singleton;    }}

網上很多資料說,這種寫法也不是安全執行緒的,singleton欄位必須定義為volatile才行。但實際上,以上代碼其實並沒有安全執行緒問題,因為Singleton1這個類並沒有狀態量。舉個例子,以下代碼才是非安全執行緒的:

public class WrongSingleton{    private static WrongSingleton singleton;        public Object state = new Object();    public static WrongSingleton getInstance()    {        if (singleton == null)        {            synchronized (WrongSingleton.class)            {                if (singleton == null)                    singleton = new WrongSingleton();            }        }        return singleton;    }}

由於cpu指令重排序的存在,我們無法確認singleton對象引用和state對象引用回寫到記憶體的順序,如果Singleton對象的引用已經由線程A回寫到了記憶體,而對象內部持有的state欄位還未完成回寫,那麼此時線程B調用getInstance()方法後,將得到一個錯誤的Singleton對象。其state引用為null。

要解決這個問題有兩個辦法:

一、把 private static WrongSingleton singleton; 改為  private static volatile Singleton singleton; 由於volatile 的可見度語意,所有對volatile變數的修改,都會立即回寫到主存,所以在Singleton建構函式返回前,state對象就已經回寫到主存了。

二、把state 對象定義為final欄位。由於final語意,final對象在建構函式完成後,其值的可見度對所有線程保持一致。

 

深入談談Java最簡單的單例設計模式

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.