一常空、簡單介紹
類的單例設(shè)計模式沽一,就是采取一定的方法保證在整個軟件系統(tǒng)中,對某個類只能存在一個對象實例漓糙,
并且該類只提供一個取得其對象實例的靜態(tài)方法
reference documentJava類加載機制(全套)
二铣缠、實現(xiàn)方法
1、餓漢式(靜態(tài)常量)
a)昆禽、代碼示例
//餓漢式(靜態(tài)變量)
class Singleton {
//2.本類內(nèi)部創(chuàng)建對象實例
private final static Singleton instance = new Singleton();
//1. 構(gòu)造器私有化, 外部能new
private Singleton() {
}
//3. 提供一個公有的靜態(tài)方法蝗蛙,返回實例對象
public static Singleton getInstance() {
return instance;
}
}
b)、優(yōu)缺點說明
- 優(yōu)點:這種寫法比較簡單醉鳖,就是在類裝載的時候就完成實例化捡硅。避免了線程同
步問題 - 缺點:在類裝載的時候就完成實例化,沒有達到Lazy Loading的效果盗棵。如果從始
至終從未使用過這個實例壮韭,則會造成內(nèi)存的浪費 - 這種方式基于classloder機制避免了多線程的同步問題北发,不過,instance在類裝載
時就實例化喷屋,在單例模式中大多數(shù)都是調(diào)用getInstance方法琳拨,但是導(dǎo)致類裝載
的原因有很多種,因此不能確定有其他的方式(或者其他的靜態(tài)方法)導(dǎo)致類
裝載屯曹,這時候初始化instance就沒有達到lazy loading的效果
c)从绘、總結(jié)
這種單例模式可用,但可能造成內(nèi)存浪費
2是牢、餓漢式(靜態(tài)代碼塊)
a)、代碼示例
//餓漢式(靜態(tài)代碼塊)
class Singleton {
//1. 構(gòu)造器私有化, 外部不能new
private Singleton() {
}
//2.本類內(nèi)部創(chuàng)建對象實例
private static Singleton instance;
static { // 在靜態(tài)代碼塊中陕截,創(chuàng)建單例對象
instance = new Singleton();
}
//3. 提供一個公有的靜態(tài)方法驳棱,返回實例對象
public static Singleton getInstance() {
return instance;
}
}
b)、優(yōu)缺點說明
- 這種方式和上面的方式其實類似农曲,只不過將類實例化的過程放在了靜態(tài)代碼塊
中社搅,也是在類裝載的時候,就執(zhí)行靜態(tài)代碼塊中的代碼乳规,初始化類的實例形葬。優(yōu)
缺點和上面是一樣的
c)、總結(jié)
這種單例模式可用暮的,但是可能造成內(nèi)存浪費
3笙以、懶漢式(線程不安全)
a)、代碼示例
class Singleton {
private static Singleton instance;
private Singleton() {}
//提供一個靜態(tài)的公有方法冻辩,當使用到該方法時猖腕,才去創(chuàng)建 instance
//即懶漢式
public static Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}
b)、優(yōu)缺點說明
- 起到了Lazy Loading的效果恨闪,但是只能在單線程下使用
- 如果在多線程下倘感,一個線程進入了if (singleton == null)判斷語句塊,還未來得及
往下執(zhí)行咙咽,另一個線程也通過了這個判斷語句老玛,這時便會產(chǎn)生多個實例。所以
在多線程環(huán)境下不可使用這種方式
c)钧敞、總結(jié)
在實際開發(fā)中蜡豹,不要使用這種方式
4、懶漢式(線程安全犁享,同步方法)
a)余素、代碼示例
// 懶漢式(線程安全,同步方法)
class Singleton {
private static Singleton instance;
private Singleton() {}
//提供一個靜態(tài)的公有方法炊昆,加入同步處理的代碼桨吊,解決線程安全問題
//即懶漢式
public static synchronized Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}
b)威根、優(yōu)缺點說明
- 解決了線程不安全問題
- 效率太低,每個線程在想獲得類的實例時候视乐,執(zhí)行g(shù)etInstance()方法都要進行
同步洛搀。而其實這個方法只執(zhí)行一次實例化代碼就夠了,后面的想獲得該類實例佑淀,
直接return就行了留美。方法進行同步效率太低
c)、總結(jié)
在實際開發(fā)中伸刃,不要使用這種方式
5谎砾、懶漢式(線程安全,同步代碼塊)
a)捧颅、代碼示例
class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if(instance == null) {
synchronized(Singleton.class){
instance = new Singleton();
}
}
return instance;
}
}
b)景图、優(yōu)缺點說明
- 這種方式,本意是想對第四種實現(xiàn)方式的改進碉哑,因為前面同步方法效率太低挚币,
改為同步產(chǎn)生實例化的的代碼塊 - 但是這種同步并不能起到線程同步的作用。跟第3種實現(xiàn)方式遇到的情形一
致扣典,假如一個線程進入了if (singleton == null)判斷語句塊妆毕,還未來得及往下執(zhí)行,
另一個線程也通過了這個判斷語句贮尖,這時便會產(chǎn)生多個實例
c)笛粘、總結(jié)
在實際開發(fā)中,不要使用這種方式
6远舅、 雙重檢查
a)闰蛔、代碼示例
// 懶漢式(線程安全,同步方法)
class Singleton {
private static volatile Singleton instance;
private Singleton() {}
//提供一個靜態(tài)的公有方法图柏,加入雙重檢查代碼序六,解決線程安全問題, 同時解決懶加載問題
public static Singleton getInstance() {
if(instance == null) {
synchronized (Singleton.class) {
if(instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
b)、優(yōu)缺點說明
- Double-Check概念是多線程開發(fā)中常使用到的蚤吹,如代碼中所示例诀,我們進行了兩
次if (singleton == null)檢查,這樣就可以保證線程安全了裁着。這樣繁涂,實例化代碼只用執(zhí)行一次,后面再次訪問時二驰,判斷if (singleton == null)扔罪,
直接return實例化對象,也避免的反復(fù)進行方法同步. - 線程安全桶雀;延遲加載矿酵;效率較高
c)唬复、總結(jié)
在實際開發(fā)中,推薦使用這種單例設(shè)計模式
7全肮、 靜態(tài)內(nèi)部類
a)敞咧、代碼示例
// 靜態(tài)內(nèi)部類完成, 推薦使用
class Singleton {
//構(gòu)造器私有化
private Singleton() {}
//寫一個靜態(tài)內(nèi)部類,該類中有一個靜態(tài)屬性 Singleton
private static class SingletonInstance {
private static final Singleton INSTANCE = new Singleton();
}
//提供一個靜態(tài)的公有方法辜腺,直接返回SingletonInstance.INSTANCE
public static Singleton getInstance() {
return SingletonInstance.INSTANCE;
}
}
b)休建、優(yōu)缺點說明
- 這種方式采用了類裝載的機制來保證初始化實例時只有一個線程。
- 靜態(tài)內(nèi)部類方式在Singleton類被裝載時并不會立即實例化评疗,而是在需要實例化
時测砂,調(diào)用getInstance方法,才會裝載SingletonInstance類百匆,從而完成Singleton的
實例化邑彪。 - 類的靜態(tài)屬性只會在第一次加載類的時候初始化,所以在這里胧华,JVM幫助我們
保證了線程的安全性,在類進行初始化時宙彪,別的線程是無法進入的矩动。
c)、總結(jié)
避免了線程不安全释漆,利用靜態(tài)內(nèi)部類特點實現(xiàn)延遲加載悲没,效率高。
在實際開發(fā)中男图,推薦使用這種單例設(shè)計模式
8示姿、 枚舉
a)、代碼示例
//使用枚舉逊笆,可以實現(xiàn)單例, 推薦
enum Singleton {
INSTANCE; //屬性
public void sayOK() {
System.out.println("ok~");
}
}
b)栈戳、優(yōu)缺點說明
- 這借助JDK1.5中添加的枚舉來實現(xiàn)單例模式。不僅能避免多線程同步問題难裆,而
且還能防止反序列化重新創(chuàng)建新的對象子檀。
+這種方式是Effective Java作者Josh Bloch 提倡的方式
c)、總結(jié)
可以使用
三乃戈、總結(jié)
- 單例模式保證了 系統(tǒng)內(nèi)存中該類只存在一個對象褂痰,節(jié)省了系統(tǒng)資源,對于一些需
要頻繁創(chuàng)建銷毀的對象症虑,使用單例模式可以提高系統(tǒng)性能 - 當想實例化一個單例類的時候缩歪,必須要記住使用相應(yīng)的獲取對象的方法,而不是使
用new - 單例模式使用的場景:需要頻繁的進行創(chuàng)建和銷毀的對象谍憔、創(chuàng)建對象時耗時過多或
耗費資源過多(即:重量級對象)匪蝙,但又經(jīng)常用到的對象主籍、工具類對象、頻繁訪問數(shù)
據(jù)庫或文件的對象(比如數(shù)據(jù)源骗污、session工廠等)