定義
保證一個類僅有一個實例莺戒,并提供一個訪問它的全局訪問點伴嗡。
Singleton:負責創(chuàng)建Singleton類自己的唯一實例,并提供一個getInstance的方法从铲,讓外部來訪問這個類的唯一實例瘪校。
- 餓漢式: private static Singleton uniqueInstance = new Singleton();
- 懶漢式 private static Singleton uniqueInstance = null;
功能
單例模式是用來保證這個類在運行期間只會被創(chuàng)建一個類實例,另外名段,單例模式還提供了一個全局唯一訪問這個類實例的訪問點阱扬,就是getInstance方法。
范圍
Java里面實現(xiàn)的單例是一個虛擬機的范圍吉嫩。因為裝載類的功能是虛擬機的价认,所以一個虛擬機在通過自己的ClassLoader裝載餓漢式實現(xiàn)單例類的時候就會創(chuàng)建一個類的實例嗅定。
懶漢式單例有延遲加載和緩存的思想
優(yōu)缺點
- 懶漢式是典型的時間換空間
- 餓漢式是典型的空間換時間
不加同步的懶漢式是線程不安全的自娩。比如,有兩個線程渠退,一個是線程A忙迁,一個是線程B,它們同時調(diào)用getInstance方法碎乃,就可能導致并發(fā)問題姊扔。
-餓漢式是線程安全的,因為虛擬機保證只會裝載一次梅誓,在裝載類的時候是不會發(fā)生并發(fā)的恰梢。
如何實現(xiàn)懶漢式的線程安全佛南?
加上synchronized即可
public static synchronized Singleton getInstance(){}
但這樣會降低整個訪問的速度,而且每次都要判斷嵌言⌒峄兀可以用雙重檢查加鎖。
雙重加鎖機制摧茴,指的是:并不是每次進入getInstance方法都需要同步绵载,而是先不同步,進入方法過后苛白,先檢查實例是否存在娃豹,如果不存在才進入下面的同步塊,這是第一重檢查购裙。進入同步塊后懂版,再次檢查實例是否存在,如果不存在躏率,就在同步的情況下創(chuàng)建一個實例定续。這是第二重檢查。
雙重加鎖機制的實現(xiàn)會使用一個關(guān)鍵字volatile禾锤,它的意思是:被volatile修飾的變量的值私股,將不會被本地線程緩存,所有對該變量的讀寫都是直接操作共享內(nèi)存恩掷,從而確保多個線程能正確的處理該變量倡鲸。
/**
* 雙重檢查加鎖的單例模式
* @author dream
*
*/
public class Singleton {
/**
* 對保存實例的變量添加volitile的修飾
*/
private volatile static Singleton instance = null;
private Singleton(){
}
public static Singleton getInstance(){
//先檢查實例是否存在,如果不存在才進入下面的同步塊
if(instance == null){
//同步塊黄娘,線程安全的創(chuàng)建實例
synchronized (Singleton.class) {
//再次檢查實例是否存在峭状,如果不存在才真正的創(chuàng)建實例
instance = new Singleton();
}
}
return instance;
}
}
一種更好的單例實現(xiàn)方式
public class Singleton {
/**
* 類級的內(nèi)部類,也就是靜態(tài)類的成員式內(nèi)部類逼争,該內(nèi)部類的實例與外部類的實例
* 沒有綁定關(guān)系优床,而且只有被調(diào)用時才會裝載,從而實現(xiàn)了延遲加載
* @author dream
*
*/
private static class SingletonHolder{
/**
* 靜態(tài)初始化器誓焦,由JVM來保證線程安全
*/
private static final Singleton instance = new Singleton();
}
/**
* 私有化構(gòu)造方法
*/
private Singleton(){
}
public static Singleton getInstance(){
return SingletonHolder.instance;
}
}
根據(jù)《高效Java第二版》中的說法胆敞,單元素的枚舉類型已經(jīng)成為實現(xiàn)Singleton的最佳方法。
package example6;
/**
* 使用枚舉來實現(xiàn)單例模式的示例
* @author dream
*
*/
public class Singleton {
/**
* 定義一個枚舉的元素杂伟,它就代表了Singleton的一個實例
*/
uniqueInstance;
/**
* 示意方法移层,單例可以有自己的操作
*/
public void singletonOperation(){
//功能樹立
}
}
本質(zhì)
控制實例數(shù)量
何時選用單例模式
當需要控制一個類的實例只能有一個,而且客戶只能從一個全局訪問點訪問它時赫粥,可以選用單例模式观话,這些功能恰好是單例模式要解決的問題。