一、引言 單例模式應該是設計模式中比較簡單的一個,因為這個模式只有一個類,但不要小看這個設計模式,這個模式可是面試的時候很常見的一個。 單例模式有什麼的用處:有一些對象我們只需要一個的時候,比如線程池,緩存,註冊表等。 也就是說這個模式的作用是:保證只有一個實例對象。 二、單例模式 先看定義:確保一 ...
一、引言
單例模式應該是設計模式中比較簡單的一個,因為這個模式只有一個類,但不要小看這個設計模式,這個模式可是面試的時候很常見的一個。
單例模式有什麼的用處:有一些對象我們只需要一個的時候,比如線程池,緩存,註冊表等。
也就是說這個模式的作用是:保證只有一個實例對象。
二、單例模式
先看定義:確保一個類只有一個實例,並提供一個全局訪問點。
開始思考,我們如何確保只有一個實例?
首先要知道我們是如何創建的對象的,這個很容易回答:用new關鍵字,只要是公開類,我們在外部就可以無限的實例化,也是就說第一步就是要將類私有化。
如何私有化:使用私有構造構造器,一旦使用私有構造器,那麼外部便不能實例化。
可一旦使用私有構造器,那麼不是只有內部才能調用這個構造器麽?既然外部不能實例化,那麼如何去調用這個私有構造器呢?
這個時候靜態方法就起作用了,我們定義一個靜態方法,通過靜態方法去調用私有構造器,問題就解決了。
通過上面的思考,代碼就已經出來了:
//單例模式實現-懶漢式 public class Singleton { //利用靜態變數記錄類的唯一實例 private static Singleton uniqueInstance; //把構造器設置為私有,只有內部才可以調用構造器 private Singleton(){} //用靜態方法實例化對象 public static Singleton getInstance(){ //如果為空則說明還沒有創建實例,這個時候我們可以創建,這個就是延時實例化,也就是傳說中的懶漢式 if(uniqueInstance==null){ uniqueInstance = new Singleton(); } return uniqueInstance; } public void showMsg(){ System.out.println("其他方法,顯示數據"); } }
這種實現方法叫做懶漢式,但這種懶漢模式存在一個問題:線程不安全,在多線程情況下,完全有可能生成多個實例,這個時候可以用synchronized關鍵字來處理。
public static synchronized Singleton getInstance(){ ... }
當然,加鎖會降低一些性能。
其實還有一種方法,那就是餓漢式:
//單例模式-餓漢式 public class Singleton1 { //初始化器重直接創建,可以保證線程安全 private static Singleton1 uniqueInstance=new Singleton1(); //靜態方法 private Singleton1(){} //直接返回 public static Singleton1 getInstance(){ return uniqueInstance; } }
這樣的方式容易產生垃圾對象,浪費一些記憶體,但是沒有加鎖,效率提高很多(一般情況下推薦使用這種方式)。
另外還有一種凡是:雙重檢查加鎖
//雙重加鎖方式 public class Singleton2 { //利用volatile 關鍵字保證多個線程正確使用uniqueInstance private volatile static Singleton2 uniqueInstance; private Singleton2(){} public static Singleton2 getInstance(){ //檢查實例,不存在則進入同步代碼塊 if(uniqueInstance==null){ //同步代碼塊 synchronized (Singleton2.class){ //進入代碼塊後,再判斷一次 if(uniqueInstance==null){ uniqueInstance=new Singleton2(); } } } return uniqueInstance; } }
這種方式可以大大提高性能,就是實現有些複雜(且不支持1.4之前的版本)
三、總結
單例模式是一個相對簡單的模式,主要的核心在私有化構造器,及暴露一個靜態方法創建實例,再考慮多線程相關情況。
設計模式相關源碼地址:https://gitee.com/yuanqinnan/pattern