0 引言
創(chuàng)建型模式(Creational Pattern)關(guān)注對象的創(chuàng)建過程,是一類最常用的設(shè)計(jì)模式,每個(gè)創(chuàng)建型模式都通過采用不同的解決方案來回答3個(gè)問題:創(chuàng)建什么(What),由誰創(chuàng)建(Who)和何時(shí)創(chuàng)建(When)。
?1 單例模式
單例模式有3個(gè)要點(diǎn):①某個(gè)類只能有一個(gè)實(shí)例;②它必須自行創(chuàng)建這個(gè)實(shí)例;③它必須自行向整個(gè)系統(tǒng)提供這個(gè)實(shí)例。
單例模式(Singleton),保證一個(gè)類僅有一個(gè)實(shí)例,并提供一個(gè)訪問它的全局訪問點(diǎn)。[DP]
1.1 餓漢單例模式
?在類加載的時(shí)候就已經(jīng)實(shí)例化,并且創(chuàng)建單例對象,以后直接使用即可。這種模式下,類加載較慢,但獲取對象的速度快,且線程安全。
public class HungrySingleton {
// 在類加載時(shí)就已經(jīng)完成了實(shí)例的初始化
private static final HungrySingleton instance = new HungrySingleton();
// 構(gòu)造器私有,防止外部通過new關(guān)鍵字創(chuàng)建對象
private HungrySingleton() {}
// 提供全局訪問點(diǎn)
public static HungrySingleton getInstance() {
return instance;
}
// 如果需要,可以添加其他方法或?qū)傩? public void showMessage() {
System.out.println("This is an instance of HungrySingleton.");
}
public static void main(String[] args) {
// 獲取單例對象
HungrySingleton instance1 = HungrySingleton.getInstance();
HungrySingleton instance2 = HungrySingleton.getInstance();
// 輸出實(shí)例,驗(yàn)證是否為同一個(gè)對象
System.out.println(instance1);
System.out.println(instance2);
// 驗(yàn)證是否為同一個(gè)對象的引用
System.out.println(instance1 == instance2);
// 調(diào)用實(shí)例方法
instance1.showMessage();
}
}
1.2 懶漢單例模式
一開始不會實(shí)例化,什么時(shí)候用就什么時(shí)候進(jìn)行實(shí)例化。這種模式下,類加載較快,但獲取對象的速度稍慢,且可能在多線程情況下出現(xiàn)線程安全問題。
?存在線程安全問題,
public class LazySingleton {
// 私有靜態(tài)實(shí)例,初始化為null
private static LazySingleton instance = null;
// 私有構(gòu)造方法,防止外部通過new關(guān)鍵字創(chuàng)建對象
private LazySingleton() {}
// 提供全局訪問點(diǎn)
public static LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
// 如果需要,可以添加其他方法或?qū)傩? public void showMessage() {
System.out.println("This is an instance of LazySingleton.");
}
public static void main(String[] args) {
// 獲取單例對象
LazySingleton instance1 = LazySingleton.getInstance();
// 調(diào)用實(shí)例方法
instance1.showMessage();
}
}
加鎖,
public class LazySingleton {
// 私有靜態(tài)實(shí)例,初始化為null
private static LazySingleton instance = null;
// 私有構(gòu)造方法,防止外部通過new關(guān)鍵字創(chuàng)建對象
private LazySingleton() {}
// 同步方法,提供全局訪問點(diǎn)
public static synchronized LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
// 如果需要,可以添加其他方法或?qū)傩? public void showMessage() {
System.out.println("This is an instance of LazySingleton.");
}
public static void main(String[] args) {
// 獲取單例對象
LazySingleton instance1 = LazySingleton.getInstance();
LazySingleton instance2 = LazySingleton.getInstance();
// 輸出實(shí)例,驗(yàn)證是否為同一個(gè)對象
System.out.println(instance1);
System.out.println(instance2);
// 驗(yàn)證是否為同一個(gè)對象的引用
System.out.println(instance1 == instance2);
// 調(diào)用實(shí)例方法
instance1.showMessage();
}
}
然而,同步方法會導(dǎo)致性能下降,因?yàn)槊看握{(diào)用getInstance()方法時(shí)都需要進(jìn)行同步。為了解決這個(gè)問題,可以使用雙重校驗(yàn)鎖(Double-Checked Locking,DCL)來實(shí)現(xiàn)更高效的懶漢單例模式:現(xiàn)在這樣,我們不用讓線程每次都加鎖,而只是在實(shí)例未被創(chuàng)建的時(shí)候再加鎖處理。同時(shí)也能保證多線程的安全。這種做法被稱為Double-Check Locking(雙重鎖定)。文章來源:http://www.zghlxwxcb.cn/news/detail-836031.html
public class LazySingletonWithDCL {
// volatile關(guān)鍵字確保instance在多線程環(huán)境下被正確初始化
private static volatile LazySingletonWithDCL instance = null;
// 私有構(gòu)造方法,防止外部通過new關(guān)鍵字創(chuàng)建對象
private LazySingletonWithDCL() {}
// 提供全局訪問點(diǎn)
public static LazySingletonWithDCL getInstance() {
if (instance == null) {
// 第一次檢查
synchronized (LazySingletonWithDCL.class) {
if (instance == null) {
// 第二次檢查
instance = new LazySingletonWithDCL();
}
}
}
return instance;
}
// 如果需要,可以添加其他方法或?qū)傩? public void showMessage() {
System.out.println("This is an instance of LazySingletonWithDCL.");
}
public static void main(String[] args) {
// 獲取單例對象
LazySingletonWithDCL instance1 = LazySingletonWithDCL.getInstance();
LazySingletonWithDCL instance2 = LazySingletonWithDCL.getInstance();
// 輸出實(shí)例,驗(yàn)證是否為同一個(gè)對象
System.out.println(instance1);
System.out.println(instance2);
// 驗(yàn)證是否為同一個(gè)對象的引用
System.out.println(instance1 == instance2);
// 調(diào)用實(shí)例方法
instance1.showMessage();
}
}
使用內(nèi)部靜態(tài)類來實(shí)現(xiàn)單例模式,這種方式的特點(diǎn)是利用了類加載機(jī)制來保證初始化實(shí)例時(shí)只有一個(gè)實(shí)例被創(chuàng)建,并且由于JVM的類加載機(jī)制,這種方式是線程安全的。只適合java。文章來源地址http://www.zghlxwxcb.cn/news/detail-836031.html
public class Singleton {
// 私有構(gòu)造方法,防止外部通過new關(guān)鍵字創(chuàng)建對象
private Singleton() {}
// 靜態(tài)內(nèi)部類,持有單例對象
private static class SingletonHolder {
// 靜態(tài)初始化器,由JVM保證線程安全
private static final Singleton INSTANCE = new Singleton();
}
// 提供全局訪問點(diǎn)
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
// 如果需要,可以添加其他方法或?qū)傩? public void showMessage() {
System.out.println("This is an instance of Singleton.");
}
public static void main(String[] args) {
// 獲取單例對象
Singleton instance1 = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
// 輸出實(shí)例,驗(yàn)證是否為同一個(gè)對象
System.out.println(instance1);
System.out.println(instance2);
// 驗(yàn)證是否為同一個(gè)對象的引用
System.out.println(instance1 == instance2);
// 調(diào)用實(shí)例方法
instance1.showMessage();
}
}
到了這里,關(guān)于設(shè)計(jì)模式-創(chuàng)建型模式-單例模式的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!