創(chuàng)建型模式(Creational Pattern)
單例模式(SingleTon)
第一種UML圖

第二種UML圖

單例模式的寫法有多種寫法,主要介紹三種:懶漢式單例,餓漢式單例,登記式單例
單例有以下特點(diǎn):
1.單例類只有一個(gè)實(shí)例
2.單例類必須自己創(chuàng)建自己的唯一對(duì)象
3.單例類必須給所有其他對(duì)象提供這一實(shí)例
單例模式確保某個(gè)類只有一個(gè)實(shí)例對(duì)象,而且自行實(shí)例化并向整個(gè)系統(tǒng)提供這個(gè)實(shí)例.在計(jì)算機(jī)系統(tǒng)中,線程池,緩存,日志對(duì)象,對(duì)話框,打印機(jī),顯卡就驅(qū)動(dòng)對(duì)象都是常見的單例,這些應(yīng)用都或多或少的具有資源管理器的功能.每臺(tái)計(jì)算機(jī)可以若干個(gè)打印機(jī),但是只有一個(gè)Printer Spooler,以避免兩個(gè)打印作業(yè)同時(shí)輸出到打印機(jī)中,每臺(tái)計(jì)算機(jī)可以有若干通信端口,系統(tǒng)應(yīng)當(dāng)集中管理這些通信端口,以避免一個(gè)通信端口同時(shí)被兩個(gè)請(qǐng)求同時(shí)調(diào)用.總之,選擇單例模式就是為了避免不一致的狀態(tài).
一.懶漢模式單例
//懶漢式單例類.在第一次調(diào)用的時(shí)候?qū)嵗约?
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通過(guò)將構(gòu)建方法限定為private避免了類在外部的實(shí)例化,在用一個(gè)虛擬機(jī)的范圍內(nèi),Singleton的唯一實(shí)例只能通過(guò)getInstance()方法訪問(wèn)
但是以上懶漢式的實(shí)現(xiàn)沒有考慮縣城安全問(wèn)題,他是縣城不安全的,并發(fā)環(huán)境下很有可能出現(xiàn)多個(gè)SingleTon實(shí)例,要實(shí)現(xiàn)線程安全,有一下三種方式,都是對(duì)getInstance方法的構(gòu)造,保證了懶漢式單例的線程安全,如果你第一次接觸單例模式,對(duì)線程安全不是很了解,可以先跳過(guò)下面的這三小條,去看餓漢式單例,等看完后面的再回頭考慮線程安全問(wèn)題:
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)內(nè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都好一些,即實(shí)現(xiàn)了線程安全,又避免了同步帶來(lái)的性能影響
二.餓漢式單例
//餓漢式單例類.在類初始化時(shí),已經(jīng)自行實(shí)例化
public class Singleton1 {?
? ? private Singleton1() {}?
? ? private static final Singleton1 single = new Singleton1();?
? ? //靜態(tài)工廠方法?
? ? public static Singleton1 getInstance() {?
? ? ? ? return single;?
? ? }?
}
餓漢式再累創(chuàng)建的同事就已經(jīng)創(chuàng)建好一個(gè)靜態(tài)的對(duì)象供系統(tǒng)使用,以后不再改變,所以天生的是線程安全的.
三.登記式單例
//類似Spring里面的方法,將類名注冊(cè),下次從里面直接獲取。
public class Singleton3 {?
? ? private static Map<String,Singleton3> map = new HashMap<String,Singleton3>();?
? ? static{?
? ? ? ? Singleton3 single = new Singleton3();?
? ? ? ? map.put(single.getClass().getName(), single);?
? ? }?
? ? //保護(hù)的默認(rèn)構(gòu)造子?
? ? protected Singleton3(){}?
? ? //靜態(tài)工廠方法,返還此類惟一的實(shí)例?
? ? 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);?
? ? }?
? ? //一個(gè)示意性的商業(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());?
? ? }?
}
登記式單例實(shí)際上維護(hù)了一組單例類的實(shí)例,將這些實(shí)例存在一個(gè)Map(登記簿)中,對(duì)于已經(jīng)登記過(guò)的實(shí)例,