提到單例模式酬诀,相信都不會(huì)陌生脏嚷,今天對(duì)其進(jìn)行總結(jié)。
以下是單例模式的特點(diǎn):
- 單例類(lèi)只能有一個(gè)實(shí)例瞒御。
- 單例類(lèi)必須自己自己創(chuàng)建自己的唯一實(shí)例父叙。
- 單例類(lèi)必須給所有其他對(duì)象提供這一實(shí)例。
種類(lèi)的話(huà)不好說(shuō)有幾類(lèi),因?yàn)橐紤]到是否在多線(xiàn)程下運(yùn)行趾唱,下面來(lái)介紹主要的幾類(lèi):
懶漢類(lèi)
//懶漢式單例類(lèi).在第一次調(diào)用的時(shí)候?qū)嵗约?
public class Singleton {
private Singleton() {
}
private static Singleton single = null;
//靜態(tài)工廠(chǎng)方法
public static Singleton getInstance() {
if (single == null) {
single = new Singleton();
}
return single;
}
}
懶漢么涌乳,所以在多線(xiàn)程下會(huì)失效,所以下面介紹三種懶漢的升級(jí)版來(lái)適應(yīng)多線(xiàn)程
- 在getinstance前加上synchronized(同步)甜癞,但這導(dǎo)致的是每次getInstance都會(huì)去同步夕晓,消耗資源。
public class Singleton {
private Singleton() {
}
private static Singleton single = null;
// 靜態(tài)工廠(chǎng)方法
public static synchronized Singleton getInstance() {
if (single == null) {
single = new Singleton();
}
return single;
}
}
- 雙重檢查鎖悠咱,它是在以上做的修改蒸辆,判斷兩次空,所以只有在第一次調(diào)用的時(shí)候會(huì)同步析既,避免了每次同步資源的消耗躬贡,注意
volatile
關(guān)鍵字。
public class Singleton {
private Singleton() {
}
private volatile static Singleton singleton = null; // 聲明成 volatile
//靜態(tài)工廠(chǎng)方法
public static Singleton getInstance() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
- 內(nèi)部靜態(tài)類(lèi)眼坏,這種我覺(jué)得是最好的拂玻,既實(shí)現(xiàn)了線(xiàn)程安全,也避免了同步帶來(lái)的性能影響宰译。
public class Singleton {
private static class LazyHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton() {
}
public static Singleton getInstance() {
return LazyHolder.INSTANCE;
}
}
餓漢類(lèi)
餓漢式是典型的空間換時(shí)間纺讲,當(dāng)類(lèi)裝載的時(shí)候就會(huì)創(chuàng)建類(lèi)的實(shí)例,不管你用不用囤屹,先創(chuàng)建出來(lái)熬甚,然后每次調(diào)用的時(shí)候,就不需要再判斷肋坚,節(jié)省了運(yùn)行時(shí)間乡括。
//餓漢式單例類(lèi).在類(lèi)初始化時(shí),已經(jīng)自行實(shí)例化
public class Singleton {
private Singleton() {
}
private static final Singleton single = new Singleton();
//靜態(tài)工廠(chǎng)方法
public static Singleton getInstance() {
return single;
}
}
這種也是我比較喜歡的智厌,因?yàn)楹?jiǎn)單易懂诲泌,但當(dāng)實(shí)現(xiàn)了Serializable接口后,反序列化時(shí)單例會(huì)被破壞铣鹏,實(shí)現(xiàn)Serializable接口需要重寫(xiě)readResolve敷扫,才能保證其反序列化依舊是單例:
private Object readResolve() throws ObjectStreamException {
return single;
}
枚舉類(lèi)
public enum Singleton {
INSTANCE;
public void whateverMethod() {
}
}
這種方式是Effective Java作者Josh Bloch 提倡的方式,它不僅能避免多線(xiàn)程同步問(wèn)題诚卸,而且還能防止反序列化重新創(chuàng)建新的對(duì)象葵第,可謂是很堅(jiān)強(qiáng)的壁壘啊,不過(guò)合溺,個(gè)人認(rèn)為由于1.5中才加入enum特性卒密,用這種方式寫(xiě)不免讓人感覺(jué)生疏,在實(shí)際工作中棠赛,我也很少看見(jiàn)有人這么寫(xiě)過(guò)哮奇。
以上就是常用的單例模式膛腐,一般的情況下,我會(huì)使用餓漢式鼎俘,只有在要明確實(shí)現(xiàn)lazy loading效果時(shí)才會(huì)使用內(nèi)部靜態(tài)類(lèi)哲身,另外,如果涉及到反序列化創(chuàng)建對(duì)象時(shí)我會(huì)試著使用枚舉的方式來(lái)實(shí)現(xiàn)單例贸伐,不過(guò)律罢,我一直會(huì)保證我的程序是線(xiàn)程安全的。