單例模式
一個(gè)類(lèi)僅有一個(gè)實(shí)例,所有其他類(lèi)對(duì)象共享該實(shí)例進(jìn)行操作
特點(diǎn):只能由自己的公共方法創(chuàng)建一個(gè)實(shí)例,只對(duì)外提供該唯一實(shí)例
應(yīng)用場(chǎng)景:資源共享文件與控制資源的操作(如日志文件,應(yīng)用配置,數(shù)據(jù)庫(kù)連接池,線程池)
應(yīng)用實(shí)例:windows task manager,數(shù)據(jù)庫(kù)連接池,OS的文件系統(tǒng),回收站...
實(shí)現(xiàn)方法:餓漢,懶漢(飽漢),雙檢索,靜態(tài)內(nèi)部類(lèi),枚舉類(lèi)
- 懶漢模式只有需要單例時(shí)才去初始化實(shí)例,線程一般不安全
- 餓漢模式在類(lèi)加載階段就將實(shí)例初始化完成,這樣保證線程安全
- 雙檢查模式,不是對(duì)這個(gè)方法進(jìn)行synchronize,僅僅在實(shí)例化步驟前進(jìn)行2次synchronize該類(lèi)
- 靜態(tài)內(nèi)部類(lèi),保證了線程安全,在內(nèi)部類(lèi)中實(shí)例化唯一實(shí)例,讀取實(shí)例沒(méi)有同步保證性能
- 枚舉模式,默認(rèn)線程安全
相關(guān)問(wèn)題:
- clone能否產(chǎn)生一個(gè)新的單例模式類(lèi)的實(shí)例?
不能,單例類(lèi)必須是final的不能被繼承,同時(shí)假如單例類(lèi)繼承于有clone方法的類(lèi),需要重寫(xiě)clone,是它拋出異常- 在getInstance()方法上同步有優(yōu)勢(shì)還是僅同步必要的塊更優(yōu)優(yōu)勢(shì)?
由于鎖有開(kāi)銷(xiāo),因此僅同步必要的塊(創(chuàng)建實(shí)例部分)就行了,其他時(shí)候僅僅是對(duì)實(shí)例的只讀操作,保證性能- 雙檢索有什么缺點(diǎn)?
需要防止初始化實(shí)例時(shí),指令重排序,因此最好對(duì)指定變量使用volatile修飾,防止指令重排序(jdk5.0以后引入)- 如何獲取更多的單例對(duì)象,如何防止?
反射機(jī)制,防止的辦法就是在構(gòu)造函數(shù)中判斷是第幾次被調(diào)用,假如不是首次調(diào)用就立即拋出異常。還有一個(gè)辦法就是使用枚舉類(lèi)模式實(shí)現(xiàn)單例
Constructor con = Singleton. class. getDeclaredConstruction( ) ;
con. setAccessible( true) ;
//通過(guò)反射獲取實(shí)例
Singleton instance = ( Singleton) con. newInstance( ) ;
枚舉類(lèi)型
- 用來(lái)表示常量,作為switch的選擇類(lèi)型,繼承自java.lang.Enum,因此不能繼承其他類(lèi)
- 在類(lèi)中添加其他方法,方法必須在實(shí)例后面,最后一個(gè)實(shí)例后需要接";"
- 枚舉集合:java.util.EnumSet,java.util.EnumMap
實(shí)現(xiàn)方法實(shí)踐
//單例模式的實(shí)現(xiàn)方式
// 懶漢(飽漢),一般沒(méi)有對(duì)方法同步,多線程可能存在生成多個(gè)實(shí)例,優(yōu)點(diǎn)是效率高,但是不安全,
// 有時(shí)候直接類(lèi)加載就初始化靜態(tài)變量,浪費(fèi)內(nèi)存
class Singleton{
private static Singleton singleton;
private Singleton(){};
public static Singleton getInstance(){
if(singleton == null){
singleton = new Singleton();
}
return singleton;
}
}
//餓漢,類(lèi)加載就產(chǎn)生實(shí)例
class Singleton{
private static Singleton singleton = new Singleton();
private Singleton(){};
public static synchronized Singleton getInstance(){
return singleton;
}
}
//雙重檢測(cè),對(duì)實(shí)例化塊進(jìn)行2次檢驗(yàn),使用同步
class Singleton{
private static volatile Singleton singleton;
private Singleton(){};
public static Singleton getInstance(){
if(singleton == null){
synchronized(Singleton.class){
if(singleton == null){
singleton = new Singleton();
}
}
}
return singleton;
}
}
//靜態(tài)內(nèi)部類(lèi),不用使用同步,線程安全.內(nèi)部類(lèi)私有性質(zhì)保證只有g(shù)etInstance能夠調(diào)用它
class Singleton{
private static class SingletonHolder{
private static final Singleton INSTANCE = new Singleton();
}
private Singleton(){};
public static Singleton getInstance(){
return SingletonHolder.INSTANCE;
}
}
//枚舉類(lèi),默認(rèn)線程安全,這種方式絕對(duì)防止反射調(diào)用私有構(gòu)造器來(lái)破壞單例
public enum Singleton{
INSTANCE;
private String name;
public void dosomething(){
doing...
}
}