單例的使用:有些對象只需要一個,比如:線程池、緩存、對話框、處理偏好設(shè)置和注冊表的對象、日志對象,充當(dāng)打印機(jī)、顯卡等設(shè)備的驅(qū)動程序的對象。
使用場景:1、要求生產(chǎn)唯一序列號;2、WEB 中的計數(shù)器,不用每次刷新都在數(shù)據(jù)庫里加一次,用單例先緩存起來;3、創(chuàng)建的一個對象需要消耗的資源過多,比如 I/O 與數(shù)據(jù)庫的連接等。
注意:其他的寫法,都是基于以下六種寫法。
/**
* 單例模式
* 定義:保證一個類僅有一個實例,并提供一個訪問它的全局訪問點(diǎn)。
*
* @author TinyDolphin
* 2017/10/22 22:35.
*/
public class Singleton {
/*//①、(懶漢式)lazy loading & 線程不安全 ,只適用于單線程環(huán)境(不好的解法)
private Singleton(){}
private static Singleton instance;
public static Singleton getInstance(){
if(instance == null)
instance = new Singleton();
return instance;
}//*/
/*//②、(懶漢式)lazy loading & 線程安全,但效率很低。(不好的解法)
// 優(yōu)點(diǎn):lazy loading,避免內(nèi)存浪費(fèi)。
// 缺點(diǎn):必須加鎖 synchronized 才能保證單例,而大部分時候我們是用不到同步的,所以不建議使用。
private Singleton(){}
private static Singleton instance;
public static synchronized Singleton getInstance(){
if(instance==null)
instance = new Singleton();
return instance;
}
//*/
/*//③、(餓漢式)no lazy loading,線程安全,但容易產(chǎn)生垃圾對象。(不好的解法)
// 優(yōu)點(diǎn):沒有加鎖,獲取對象得到速度快,執(zhí)行效率提高
// 缺點(diǎn):類加載時就初始化,浪費(fèi)內(nèi)存,且類加載較慢
private Singleton(){}
private static Singleton instance = new Singleton();
public static Singleton getInstance(){
return instance;
}
//*/
/*//④、雙檢鎖/雙重校驗鎖(DCL,即 double-checked locking),lazy loading & 線程安全(可行的解法)
// 優(yōu)點(diǎn):資源利用率高,第一次執(zhí)行g(shù)etInstance 時單例對象才被實例化,效率高
// 缺點(diǎn):第一次加載時稍慢,在高并發(fā)環(huán)境下也有一定的缺陷(發(fā)生的概率很?。? private Singleton(){}
private volatile static Singleton instance;
public static Singleton getInstance(){
if(instance == null){
synchronized (Singleton.class){
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
//*/
/*//⑤、登記式/靜態(tài)內(nèi)部類 lazy loading & 線程安全 (推薦使用,包括面試)
// 第一次類加載并不會初始化 Instance,只有第一次調(diào)用 getInstance 方法時,虛擬機(jī)加載 SingletonHolder 并初始化 Instance
private Singleton(){}
private static class SingletonHolder{
private static final Singleton INSTANCE = new Singleton();
}
public static final Singleton getInstance(){
return SingletonHolder.INSTANCE;
}
//*/
}
//⑥、實現(xiàn)單例模式的最佳方法。更簡潔,自動支持序列化機(jī)制,絕對防止多次實例化。但是大部分應(yīng)用開發(fā)很少用枚舉,可讀性不高,(不建議用)。
public enum Singleton {
INSTANCE;
public void whateverMethod(){}
}
下面擴(kuò)展一種:單例統(tǒng)一管理類
//用 SingletonManager 將多種的單例類統(tǒng)一管理,在使用時根據(jù) key 獲取對象對應(yīng)類型的對象(嚴(yán)格意義上,不能稱為單例,而算是如何管理類對象)
public class SingletonManager {
private static Map<String,Object> objectMap = new HashMap<String,Object>();
private SingletonManager(){}
public static void registerService(String key,Object instance){
if(!objectMap.containsKey(key)){
objectMap.put(key,instance);
}
}
public static Object getService(String key){
return objectMap.get(key);
}
}
經(jīng)驗之談:
第 ① 種和第 ② 種懶漢式:不建議使用;
第 ③ 種餓漢式:建議使用;
第 ⑤ 種登記方式:在明確實現(xiàn) lazy loading 效果下使用(強(qiáng)烈建議使用,面試加分項);
第 ⑥ 種枚舉方式:涉及到反序列化創(chuàng)建對象;
第 ④ 種雙檢鎖方式:其他特殊的需求。