單例設計模式
通過單例模式能夠保證系統中一個類僅僅有一個實例并且該實例易于外界訪問,從而方便對實例個數的控制并節約系統資源。假設希望在系統中某個類的對象僅僅能存在一個,單例模式是最好的解決方式。
關于單例設計模式的動機
假設不使用機制對窗體對象進行唯一化,將彈出多個窗體。假設這些窗體顯示的內容全然一致,則是反復對象。浪費內存資源;假設這些窗體顯示的內容不一致。則意味著在某一瞬間系統有多個狀態,與實際不符。也會給用戶帶來誤解,不知道哪一個才是真實的狀態。
因此有時確保系統中某個對象的唯一性即一個類僅僅能有一個實例非常重要。
怎樣保證一個類僅僅有一個實例而且這個實例易于被訪問呢?定義一個全局變量能夠確保對象隨時都能夠被訪問。但不能防止我們實例化多個對象。
一個更好的解決的方法是讓類自身負責保存它的唯一實例。這個類能夠保證沒有其它實例被創建。而且它能夠提供一個訪問該實例的方法。
這就是單例模式的模式動機
關于單例設計模式的要點
從詳細實現角度來說,就是下面三點:一是單例模式的類僅僅提供私有的構造函數,二是類定義中含有一個該類的靜態私有對象,三是該類提供了一個靜態的公有的函數用于創建或獲取它本身的靜態私有對象。
Java實例:
我覺得使用單例模式的時機是當實例存在多個會引起程序邏輯錯誤的時候。比方類似有序的號碼生成器這種東西。怎么能夠同意一個應用上存在多個呢?
餓漢式單例
public class Singleton { private static Singleton singleton = new Singleton(); private Singleton(){} public static Singleton getInstance(){ return singleton; }
}
懶漢式單例
public class Singleton { private static Singleton singleton; private Singleton(){} public static synchronized Singleton getInstance(){ if(singleton==null){ singleton = new Singleton(); } return singleton; }
}
可是這樣的單例類型在多線程中是不安全。有可能會出現兩個INSTANCE,為什么呢?假設當唯一實例尚未創建時,有兩個線程同一時候調用創建方法,那么它們同一時候沒有檢測到唯一實例的存在,從而同一時候各自創建了一個實例,這樣就有兩個實例被構造出來,從而違反了單例模式中實例唯一的原則。 解決問題的辦法是為指示類是否已經實例化的變量提供一個相互排斥鎖(詳見雙重鎖單例。盡管這樣會減少效率)。
餓漢式是線程安全的,在類創建的同一時候就已經創建好一個靜態的對象供系統使用,以后不在改變。
懶漢式適合單線程。多線程情況下假設在創建實例對象時不加上synchronized則會導致對對象的訪問不是線程安全的。
從實現方式來講他們最大的差別就是懶漢式是延時載入,?
他是在須要的時候才創建對象,而餓漢式在載入類時創建實例。?
?餓漢式無需關注多線程問題、寫法簡單明了、能用則用。可是它是載入類時創建實例、所以假設是一個工廠模式、緩存了非常多實例、那么就得考慮效率問題,由于這個類一載入則把全部實例無論用不用一塊創建。 懶漢式的長處是延時載入、缺點是應該用同步。
在內存中僅僅有一個對象。節省內存空間。
避免頻繁的創建銷毀對象,能夠提高性能。
避免對共享資源的多重占用。
能夠全局訪問。
適用場景:
我總結了一下我所知道的適合使用單例模式的場景:
須要頻繁實例化然后銷毀的對象。
創建對象時耗時過多或者耗資源過多,但又經經常使用到的對象。
有狀態的工具類對象。
頻繁訪問數據庫或文件的對象。
以及其它我沒用過的全部要求僅僅有一個對象的場景。
單例模式注意事項:
僅僅能使用單例類提供的方法得到單例對象,不要使用反射。否則將會實例化一個新對象。
不要做斷開單例類對象與類中靜態引用的危急操作。
多線程使用單例使用共享資源時,注意線程安全問題。
雙重鎖形式單例(懶漢式進階版。哈哈)
public static class Singleton{private static Singleton instance=null;private Singleton(){//do something}public static Singleton getInstance(){if(instance==null){synchronized(Singleton.class){if(null==instance){instance=new Singleton();}}}return instance;}
}
(有些朋友搞不懂為什么要推斷兩次Instance==null,由于在多線程中第一次推斷時可能有兩個或者多個instance==null。那么在synchronized鎖里第一個instance已經new出來了,第二個或者后面進入的假設不推斷就會反復new對象出來,所以在里面多一層推斷確保Instance實例僅僅有一個)這樣還是有一個缺點就是:就是在一個線程還未全然初始化該對象時,而那個變量已經顯示為被初始化,那么其它線程可能去使用這個未被全然初始化的實例,造成系統的崩潰。
只是這個在java5以上能夠安全執行。
第二種完美實現的實現既線程安全又延遲載入的模式(Initialization on demand holder)使用靜態內部類 ?演示樣例:
Public class Singleton{Private Singleton(){};Public static class Singleton1{Private static final Singleton instance = new Singleton();
} Public static Singleton getInstance(){Return Singleton1.instance;
}
}
這樣就能保證在第一次調用getInstance()方法時,才會去初始化instance實例,并且該實例被定義為static,僅僅會被初始化一次。(這樣的方法是網上看的,我還未用過,以后能夠試試。哈哈
