創(chuàng)建型模式(Creational Pattern)
單例模式(SingleTon)
第一種UML圖
第二種UML圖
單例模式的寫法有多種寫法,主要介紹三種:懶漢式單例,餓漢式單例,登記式單例
單例有以下特點:
1.單例類只有一個實例
2.單例類必須自己創(chuàng)建自己的唯一對象
3.單例類必須給所有其他對象提供這一實例
單例模式確保某個類只有一個實例對象,而且自行實例化并向整個系統(tǒng)提供這個實例.在計算機系統(tǒng)中,線程池,緩存,日志對象,對話框,打印機,顯卡就驅動對象都是常見的單例,這些應用都或多或少的具有資源管理器的功能.每臺計算機可以若干個打印機,但是只有一個Printer Spooler,以避免兩個打印作業(yè)同時輸出到打印機中,每臺計算機可以有若干通信端口,系統(tǒng)應當集中管理這些通信端口,以避免一個通信端口同時被兩個請求同時調用.總之,選擇單例模式就是為了避免不一致的狀態(tài).
一.懶漢模式單例
//懶漢式單例類.在第一次調用的時候實例化自己
public class Singleton {?
? ? private Singleton() {}?
? ? private static Singleton single=null;?
? ? //靜態(tài)工廠方法?
? ? public static Singleton getInstance() {?
? ? ? ? if (single == null) {? ?
? ? ? ? ? ? single = new Singleton();?
? ? ? ? }? ?
? ? ? ? return single;?
? ? }?
}
SingleTon通過將構建方法限定為private避免了類在外部的實例化,在用一個虛擬機的范圍內,Singleton的唯一實例只能通過getInstance()方法訪問
但是以上懶漢式的實現(xiàn)沒有考慮縣城安全問題,他是縣城不安全的,并發(fā)環(huán)境下很有可能出現(xiàn)多個SingleTon實例,要實現(xiàn)線程安全,有一下三種方式,都是對getInstance方法的構造,保證了懶漢式單例的線程安全,如果你第一次接觸單例模式,對線程安全不是很了解,可以先跳過下面的這三小條,去看餓漢式單例,等看完后面的再回頭考慮線程安全問題:
1.getInstance方法上加同步
publicstaticsynchronized Singleton getInstance() {
? ? ? ? ? ? if(single ==null) {? ?
? ? ? ? ? ? ? ? single =new Singleton();?
? ? ? ? ? ? }? ?
? ? ? ? ? ? return single;?
? ? }
2.雙重檢查鎖定
public static Singleton getInstance() {
? ? ? ? if (singleton == null) {? ?
? ? ? ? ? ? synchronized (Singleton.class) {? ?
? ? ? ? ? ? ? if (singleton == null) {? ?
? ? ? ? ? ? ? ? ? singleton = new Singleton();?
? ? ? ? ? ? ? }? ?
? ? ? ? ? ? }? ?
? ? ? ? }? ?
? ? ? ? return singleton;?
? ? }
3.靜態(tài)內部類
public class Singleton {
? ? private static class LazyHolder {? ?
? ? ? private static final Singleton INSTANCE = new Singleton();? ?
? ? }? ?
? ? private Singleton (){}? ?
? ? public static final Singleton getInstance() {? ?
? ? ? return LazyHolder.INSTANCE;? ?
? ? }? ?
}
第三種比上面1.2都好一些,即實現(xiàn)了線程安全,又避免了同步帶來的性能影響
二.餓漢式單例
//餓漢式單例類.在類初始化時坐桩,已經自行實例化
public class Singleton1 {?
? ? private Singleton1() {}?
? ? private static final Singleton1 single = new Singleton1();?
? ? //靜態(tài)工廠方法?
? ? public static Singleton1 getInstance() {?
? ? ? ? return single;?
? ? }?
}
餓漢式再累創(chuàng)建的同事就已經創(chuàng)建好一個靜態(tài)的對象供系統(tǒng)使用,以后不再改變,所以天生的是線程安全的.
三.登記式單例
//類似Spring里面的方法瓦侮,將類名注冊潦刃,下次從里面直接獲取。
public class Singleton3 {?
? ? private static Map<String,Singleton3> map = new HashMap<String,Singleton3>();?
? ? static{?
? ? ? ? Singleton3 single = new Singleton3();?
? ? ? ? map.put(single.getClass().getName(), single);?
? ? }?
? ? //保護的默認構造子?
? ? protected Singleton3(){}?
? ? //靜態(tài)工廠方法,返還此類惟一的實例?
? ? public static Singleton3 getInstance(String name) {?
? ? ? ? if(name == null) {?
? ? ? ? ? ? name = Singleton3.class.getName();?
? ? ? ? ? ? System.out.println("name == null"+"--->name="+name);?
? ? ? ? }?
? ? ? ? if(map.get(name) == null) {?
? ? ? ? ? ? try {?
? ? ? ? ? ? ? ? map.put(name, (Singleton3) Class.forName(name).newInstance());?
? ? ? ? ? ? } catch (InstantiationException e) {?
? ? ? ? ? ? ? ? e.printStackTrace();?
? ? ? ? ? ? } catch (IllegalAccessException e) {?
? ? ? ? ? ? ? ? e.printStackTrace();?
? ? ? ? ? ? } catch (ClassNotFoundException e) {?
? ? ? ? ? ? ? ? e.printStackTrace();?
? ? ? ? ? ? }?
? ? ? ? }?
? ? ? ? return map.get(name);?
? ? }?
? ? //一個示意性的商業(yè)方法?
? ? public String about() {? ? ?
? ? ? ? return "Hello, I am RegSingleton.";? ? ?
? ? }? ? ?
? ? public static void main(String[] args) {?
? ? ? ? Singleton3 single3 = Singleton3.getInstance(null);?
? ? ? ? System.out.println(single3.about());?
? ? }?
}
登記式單例實際上維護了一組單例類的實例,將這些實例存在一個Map(登記簿)中,對于已經登記過的實例,