定義
保證一個(gè)類僅有一個(gè)實(shí)例,并提供一個(gè)訪問(wèn)它的全局訪問(wèn)點(diǎn)。
單例的使用場(chǎng)景
在一個(gè)系統(tǒng)中,要求一個(gè)類有且僅有一個(gè)對(duì)象,具體使用場(chǎng)景如下:
- 整個(gè)項(xiàng)目需要一個(gè)共享訪問(wèn)點(diǎn)或共享數(shù)據(jù)。
- 創(chuàng)建一個(gè)對(duì)象需要耗費(fèi)的資源過(guò)多,比如訪問(wèn) I/O或者數(shù)據(jù)庫(kù)等資源。
- 工具類對(duì)象。
單例模式的6六種寫法
1. 餓漢模式
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {
}
public static Singleton getInstance(){
return instance;
}
}
優(yōu)點(diǎn):
- 這種方式在類加載時(shí)就完成初始化了,獲取對(duì)象但速度快。
- 避免多線程但同步問(wèn)題。
缺點(diǎn):
- 類加載較慢。
- 沒(méi)有達(dá)到懶加載的效果,如果從始至終都未使用果這個(gè)實(shí)例,這會(huì)造成內(nèi)存的浪費(fèi)。
2. 懶漢模式(線程不安全)
public class Singleton {
private static Singleton instance;
private Singleton() {
}
public static Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
優(yōu)點(diǎn):
- 節(jié)省資源
缺點(diǎn):
- 第一次實(shí)例化對(duì)象時(shí)較慢。
- 多線程時(shí)不能正常工作。
3. 懶漢模式(線程安全)
public class Singleton {
private static Singleton instance;
private Singleton() {
}
public static synchronized Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
優(yōu)點(diǎn):
- 多線程中很好的工作。
缺點(diǎn):
- 每次調(diào)用
getInstance
方法時(shí)都需要同步,這會(huì)造成不必要的同步開(kāi)銷。
大部分時(shí)候我們是用不到同步的,所以,不建議用這種模式。
4. 雙重檢查模式
public class Singleton {
private volatile static Singleton instance;
private Singleton() {
}
public static Singleton getInstance(){
if(instance == null){
synchronized (Singleton.class) {
if(instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
優(yōu)點(diǎn):
- 資源利用率高。
- 避免多余同步。
- 線程安全。
缺點(diǎn):
- 使用了
volatile
或多或少會(huì)影響性能。 - 第一次實(shí)例化對(duì)象時(shí)較慢。
- 在高并發(fā)某些情況下會(huì)出現(xiàn)失效問(wèn)題。
DCL
(Double Check Lock) 在高并發(fā)環(huán)境下也會(huì)有一定的缺陷,DCL
雖然在一定程度上解決了資源的消耗、多余的同步、線程安全問(wèn)題等問(wèn)題,但還是在某些情況會(huì)出現(xiàn)失效的問(wèn)題,也就是DCL
失效。這里建議用靜態(tài)內(nèi)部類單例模式來(lái)代替DCL
。
5. 靜態(tài)內(nèi)部類單例模式 (推薦使用)
public class Singleton {
private Singleton() {
}
public static Singleton getInstance(){
return SingletonHolder.sInstance;
}
private static class SingletonHolder {
private static final Singleton sInstance = new Singleton();
}
}
第一次加載
Singleton
類時(shí)并不會(huì)初始化sInstance
。 只有在第一次調(diào)用getInstance
方法時(shí)虛擬機(jī)才會(huì)加載SingletonHolder
并初始化 sInstance。
優(yōu)點(diǎn):
- 資源利用率高。
- 避免多余同步。
- 線程安全。
缺點(diǎn):
- 暫無(wú)
6. 枚舉單例
public enum Singleton {
INSTANCE;
public void doSomeThing() {
}
}
優(yōu)點(diǎn):
- 任何情況下都是單例。
- 默認(rèn)線程安全。
缺點(diǎn):
- 簡(jiǎn)單
- 可讀性不高。
總結(jié):到這里6種單例寫法已介紹完,至于選擇那種形勢(shì)的單例模式,取決與你項(xiàng)目本身情況:是否復(fù)雜的高并發(fā)環(huán)境,或者是否需要控制單例對(duì)象的資源消耗。