單例模式確保某個(gè)類只有一個(gè)實(shí)例改基,而且自行實(shí)例化并向整個(gè)系統(tǒng)提供這個(gè)實(shí)例暑诸。
Singleton通過將構(gòu)造方法限定為private避免了類在外部被實(shí)例化县恕,在同一個(gè)虛擬機(jī)范圍內(nèi)惨缆,Singleton的唯一實(shí)例只能通過getInstance()方法訪問(事實(shí)上糜值,通過Java反射機(jī)制是能夠?qū)嵗瘶?gòu)造方法為private的類的,那基本上會(huì)使所有的Java單例實(shí)現(xiàn)失效坯墨。此問題在此處不做討論寂汇。)
單例模式有以下特點(diǎn):
- 單例類只能有一個(gè)實(shí)例
- 單例類必須自己創(chuàng)建自己的唯一實(shí)例
- 單例類必須給所有其他對象提供這一實(shí)例
單例模式有以下有點(diǎn):
- 由于只有一個(gè)實(shí)例,故可以減少內(nèi)存開銷
- 可以避免對資源的多重占用捣染,避免對同一資源進(jìn)行多種操作
- 設(shè)置了全局的資源訪問骄瓣,可以優(yōu)化和共享全局資源訪問
單例模式的幾種實(shí)現(xiàn)方法
- 懶漢單例
public class Singleton {
private static Singleton single=null;
private Singleton() { }
public static Singleton getInstance() {
if(single==null) {
single=new Singleton();
}
return single;
}
}
特點(diǎn):在第一次調(diào)用的時(shí)候?qū)嵗约?優(yōu)點(diǎn):在需要的時(shí)候才去加載
缺點(diǎn):在多線程的環(huán)境下,會(huì)出現(xiàn)線性不安全的情況
懶漢式單例的實(shí)現(xiàn)沒有考慮線程安全問題耍攘,它是線程不安全的榕栏,并發(fā)環(huán)境下很可能出現(xiàn)多個(gè)Singleton實(shí)例畔勤,要實(shí)現(xiàn)線程安全,有以下三種方式扒磁,都是對getInstance這個(gè)方法改造庆揪,保證了懶漢式單例的線程安全.
1.1 在getInstance方法上加同步
public class Singleton {
private static Singleton single=null;
private Singleton() { }
public static synchronized Singleton getInstance() {
if(single==null) {
single=new Singleton();
}
return single;
}
}
優(yōu)點(diǎn):解決了線性同步問題
缺點(diǎn):每次調(diào)用都要判斷同步鎖,導(dǎo)致效率低
1.2 雙重檢查鎖
public class Singleton {
private static Singleton single=null;
private Singleton() { }
public static Singleton getInstance() {
if(single==null) {
synchronized(Singleton.class) {
if(single==null) {
single=new Singleton();
}
}
}
return single;
}
}
優(yōu)點(diǎn):在并發(fā)量不高妨托、安全性不高的情況下可以很好的運(yùn)行,在getInstance中做了兩次null檢查缸榛,
確保了只有第一次調(diào)用單例的時(shí)候才會(huì)做同步,這樣也是線程安全的兰伤,同時(shí)避免了每次都同步的性能損耗
缺點(diǎn):在不同的編譯環(huán)境下可能出現(xiàn)不同的問題
1.3 靜態(tài)內(nèi)部類
public class Singleton {
private static class Holder {
private static final Singleton INSTANCE=new Singleton();
}
private Singleton() { }
public static final Singleton getInstance() {
return Holder.INSTANCE;
}
}
優(yōu)點(diǎn):延遲加載内颗、線性安全、減少內(nèi)存消耗
這種比上面1.1敦腔、1.2都好一些均澳,既實(shí)現(xiàn)了線程安全,又避免了同步帶來的性能影響符衔。
- 餓漢單例
public class Singleton {
private Singleton() {}
private static final Singleton single=new Singleton();
//靜態(tài)工廠方法
public static Singleton getInstance() {
return single;
}
}
特點(diǎn):在類初始化時(shí)找前,已經(jīng)自行實(shí)例化
餓漢式在類創(chuàng)建的同時(shí)就已經(jīng)創(chuàng)建好一個(gè)靜態(tài)的對象供系統(tǒng)使用,以后不再改變柏腻,所以天生是線程安全的纸厉。
- 枚舉
public enum Singleton {
INSTANCE;
public void whateverMethod() { }
}
它不僅能避免多線程同步問題,而且還能防止反序列化重新創(chuàng)建新的對象五嫂,可謂是很堅(jiān)強(qiáng)的壁壘啊颗品,不過,個(gè)人認(rèn)為由于1.5中才加入enum特性沃缘,用這種方式寫不免讓人感覺生疏躯枢,在實(shí)際工作中,我也很少看見有人這么寫過槐臀。
餓漢式和懶漢式區(qū)別 :
- 餓漢就是類一旦加載锄蹂,就把單例初始化完成,保證getInstance的時(shí)候水慨,單例是已經(jīng)存在的了得糜,
- 而懶漢比較懶朝抖,只有當(dāng)調(diào)用getInstance的時(shí)候治宣,才回去初始化這個(gè)單例。
- 餓漢式天生就是線程安全的,可以直接用于多線程而不會(huì)出現(xiàn)問題侮邀,
- 懶漢式本身是非線程安全的坏怪,為了實(shí)現(xiàn)線程安全有幾種寫法,分別是上面的1.1绊茧、1.2铝宵、1.3,這三種實(shí)現(xiàn)在資源加載和性能方面有些區(qū)別按傅。