定義:java
單例模式,是一種經常使用的軟件設計模式。在它的核心結構中只包含一個被稱爲單例的特殊類。經過單例模式能夠保證系統中一個類只有一個實例。即一個類只有一個對象實例。編程
特色:設計模式
一、單例類只能有一個實例。
二、單例類必須本身本身建立本身的惟一實例。
三、單例類必須給全部其餘對象提供這一實例安全
單例模式的要點:服務器
1,私有的構造方法多線程
2,指向本身實例的私有靜態引用併發
3,以本身實例爲返回值的靜態的公有的方法jvm
單例模式根據實例化對象時機的不一樣分爲兩種:分佈式
一種是餓漢式單例,一種是懶漢式單例。函數
餓漢式單例在單例類被加載時候,就實例化一個對象交給本身的引用;而懶漢式在調用取得實例方法的時候纔會實例化對象。
代碼以下:
餓漢式單例
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; } }
單例模式還有一種比較常見的形式:雙重鎖的形式
public class Singleton{
private static volatile Singleton instance=null;
private Singleton(){
//do something }
public static Singleton getInstance(){
if(instance==null){
synchronized(SingletonClass.class){
if(instance==null){ instance=new Singleton(); } } }
return instance; } }
這個模式將同步內容下方到if內部,提升了執行的效率,沒必要每次獲取對象時都進行同步,只有第一次才同步,建立了之後就不必了。
因此若是面對高併發的狀況,並且採用的是懶漢模式,最好的選擇就是雙重判斷加同步的方式。
單例模式的優勢:
1,在內存中只有一個對象,節省內存空間。
2,避免頻繁的建立銷燬對象,能夠提升性能。
3,避免對共享資源的多重佔用。
4,能夠全局訪問。
單例模式的優勢:
1,擴展困難,因爲getInstance靜態函數沒有辦法生成子類的實例。若是要拓展,只有重寫那個類。
2,隱式使用引發類結構不清晰。
3,致使程序內存泄露的問題。
適用場景:
因爲單例模式的以上優勢,因此是編程中用的比較多的一種設計模式。如下爲使用單例模式的場景:
1,須要頻繁實例化而後銷燬的對象。
2,建立對象時耗時過多或者耗資源過多,但又常常用到的對象。
3,資源共享的狀況下,避免因爲資源操做時致使的性能或損耗等
4,控制資源的狀況下,方便資源之間的互相通訊。
單例模式注意事項:
只能使用單例類提供的方法獲得單例對象,不要使用反射,不然將會實例化一個新對象。
不要作斷開單例類對象與類中靜態引用的危險操做。
多線程使用單例使用共享資源時,注意線程安全問題。
關於Java中單例模式的一些常見問題:
單例模式的對象長時間不用會被jvm垃圾收集器收集嗎
除非人爲地斷開單例中靜態引用到單例對象的聯接,不然jvm垃圾收集器是不會回收單例對象的。
jvm卸載類的斷定條件以下:
1,該類全部的實例都已經被回收,也就是java堆中不存在該類的任何實例。
2,加載該類的ClassLoader已經被回收。
3,該類對應的java.lang.Class對象沒有任何地方被引用,沒法在任何地方經過反射訪問該類的方法。
只有三個條件都知足,jvm纔會在垃圾收集的時候卸載類。顯然,單例的類不知足條件一,所以單例類也不會被回收。
在一個jvm中會出現多個單例嗎
在分佈式系統、多個類加載器、以及序列化的的狀況下,會產生多個單例,這一點是無庸置疑的。那麼在同一個jvm中,會不會產生單例呢?使用單例提供的getInstance()方法只能獲得同一個單例,除非是使用反射方式,將會獲得新的單例。
代碼以下:
Class c = Class.forName(Singleton.class.getName());
Constructor ct = c.getDeclaredConstructor();
ct.setAccessible(true); Singleton singleton = (Singleton)ct.newInstance();
這樣,每次運行都會產生新的單例對象。因此運用單例模式時,必定注意不要使用反射產生新的單例對象。
在getInstance()方法上同步有優點仍是僅同步必要的塊更優優點?
由於鎖定僅僅在建立實例時纔有意義,而後其餘時候實例僅僅是隻讀訪問的,所以只同步必要的塊的性能更優,而且是更好的選擇。
缺點:只有在第一次調用的時候,纔會出現生成2個對象,才必需要求同步。而一旦singleton 不爲null,系統依舊花費同步鎖開銷,有點得不償失。
單例類能夠被繼承嗎
根據單例實例構造的時機和方式不一樣,單例模式還能夠分紅幾種。但對於這種經過私有化構造函數,靜態方法提供實例的單例類而言,是不支持繼承的。
這種模式的單例實現要求每一個具體的單例類自身來維護單例實例和限制多個實例的生成。但能夠採用另一種實現單例的思路:登記式單例,來使得單例對繼承開放。
Java知音公衆號推送一些Java必備的知識,讓您在閒暇之餘鞏固一下本身的知識體系 ,擴充一下本身的知識面。快利用瑣碎時間給本身充電吧!