單例模式的目的
創(chuàng)建對象,確保對象的唯一性赁炎,在同一個系統(tǒng)中醉箕,對象只有一個實例.讓類自己負(fù)責(zé)保存它的唯一實例钾腺,提供一個訪問實例的方法.
單例模式概述
單例模式(Singleton Pattern):單例模式確保某一個類只有一個實例徙垫,而且自行實例化并向整個系統(tǒng)提供這個實例,這個類稱為單例類放棒,它提供全局訪問的方法姻报。
要點
- 類只能有一個實例
- 類自己負(fù)責(zé)創(chuàng)建實例
- 提供訪問實例的方法
實現(xiàn)分類
- 餓漢式
- 懶漢式
餓漢式
pulic class Singleton{
//唯一實例
private static Singleton instance = new Singleton();
//只能由類自己負(fù)責(zé)創(chuàng)建實例
private Singleton(){
}
}
//外部訪問實例的方法
public static getInstance(){
return instance;
}
從代碼中可以看出,在定義靜態(tài)變量的時候就實例化了單例類.在類加載的時候间螟,靜態(tài)方法會先加載吴旋,所以單例對象在類加載的時候九被創(chuàng)建了,靜態(tài)變量只加載一次厢破,可以保證單例對象的唯一性荣瑟,并且是線程安全的.但是在類加載的時候就創(chuàng)建,會影響程序的效率.
懶漢式
public class Singleton{
//唯一實例
private static Singleton instance = null;
//只能由類自己負(fù)責(zé)創(chuàng)建實例
private Singleton(){
}
//外部訪問實例的方法
public static getInstance(){
if (interface == null)
instance = new Singleton();
}
return instance;
}
}
懶漢式在需要的時候才實例化,在類加載的時候不進(jìn)行實例化,能起到懶加載的作用详幽,但是如果在多線程的情況下橄仍,比如線程A和線程B同時調(diào)用getInstance(),可能會導(dǎo)致并發(fā)問題怠惶,所以要在getInstance()前加上synchronized進(jìn)行同步酬凳,但是這樣每次都要判斷取募,會降低訪問速度.可以用雙重檢查鎖.
雙重檢查鎖的第一次檢查是檢查實例是否存在壮吩,如果不存在再進(jìn)入下面的同步塊不皆,而不是直接進(jìn)入同步塊.第二重檢查是進(jìn)入同步塊后贯城,再檢查實例是否存在,如果不存在霹娄,就在同步的情況下創(chuàng)景實例.
/**
*雙重檢查鎖的單例模式
*/
public class Singleton{
/**
* 對保存實例的變量添加volitile的修飾
* 唯一實例
*/
private volatile static Singleton instance = null;
//只能由類自己負(fù)責(zé)創(chuàng)建實例
private Singleton(){
}
//外部訪問實例的方法
public static getInstance(){
//第一重檢查能犯,檢查實例是否存在,如果不存在犬耻,再進(jìn)入同步代碼塊
if (interface == null)
//鎖定代碼塊
synchronized (Singleton.class){
//第二重檢查
if (instance == null) {
instance = new Singleton();//創(chuàng)建單例實例
}
}
}
return instance;
}
}
更好的實現(xiàn)方式
餓漢單例模式在類加載的時候就會創(chuàng)建悲雳,不能實現(xiàn)延時加載,如果以后不用香追,還會占據(jù)內(nèi)存合瓢,還會影響程序的加載效率.懶漢單例模式需確保線程安全,性能會受到影響.比較好的實現(xiàn)方式是結(jié)合二者的優(yōu)點透典,使用靜態(tài)內(nèi)部類來實現(xiàn)單例模式.
public class Singleton {
/**
* 類級的內(nèi)部類晴楔,也就是靜態(tài)類的成員式內(nèi)部類,
*該內(nèi)部類的實例與外部類的實例沒有綁定關(guān)系峭咒,而且只有被調(diào)用時才會裝載税弃,從而實現(xiàn)了延遲加載
*/
private static class SingletonHolder{
/**
* 靜態(tài)初始化器,由JVM來保證線程安全
*/
private static Singleton instance = new Singleton();
}
/**
* 私有化構(gòu)造方法
* 只能由類自己負(fù)責(zé)創(chuàng)建實例
*/
private Singleton(){
}
public static Singleton getInstance(){
return SingletonHolder.instance;
}
}
使用靜態(tài)內(nèi)部類凑队,能實現(xiàn)延時加載则果,保證線程安全,又不影響系統(tǒng)性能.
枚舉類型實現(xiàn)
根據(jù)<Effective Java>第二版漩氨,單元素的枚舉類型已經(jīng)成為實現(xiàn)Singleton的最佳方法西壮。
/**
* 使用枚舉來實現(xiàn)單例模式
*
*/
public class Singleton {
/**
* 定義一個枚舉的元素,它就代表了Singleton的一個實例
*/
uniqueInstance;
/**
* 單例的方法
*/
public void singletonOperation(){
//功能樹立
}
}
單例的使用場景
系統(tǒng)只需要要一個實例對象叫惊,而且客戶調(diào)用類的單個實例只允許使用一個公共訪問點款青,除了該公共訪問點,不能通過其他途徑訪問該實例霍狰。