定義:一個類有且僅有一個實例,並且自行實例化向整個系統提供。
作用:解決一個全局使用的類頻繁地創建與銷燬的問題。
優點:減少內存開銷,避免對資源的多重佔用。
缺點:沒有接口,不能繼承。
實現方式:餓漢式,懶漢式,雙重檢查鎖,靜態私有內部類,枚舉
餓漢式
/* 餓漢式單例類*/
public class Singleton {
private Singleton(){
}
private static Singleton instance = new Singleton();
public static Singleton getInstance(){
return instance;
}
}
缺點:不支持併發,只能在單線程中使用,加載時就已經創建好了實例,不管用不用。
懶漢式
懶漢式(不支持併發)
/* 懶漢式-- 不支持併發 */
public class Singleton2 {
private Singleton2(){
}
private static Singleton2 instance = null;
private static Singleton2 getInstance(){
if (instance == null){
instance = new Singleton2();
}
return instance;
}
}
缺點:不支持併發,只能在單線程中使用。
優點:只有在調用獲取實例的方法時才創建實例。
懶漢式(支持併發)
/*餓漢式--支持併發*/
public class Singleton3 {
private Singleton3(){
}
private static Singleton3 instance = null;
private synchronized static Singleton3 getInstance(){
if (instance == null){
instance = new Singleton3();
}
return instance;
}
}
缺點:synchronized鎖住了整個方法,當有多個線程需要訪問方法時,不管實例有沒有創建,都需要排隊等待才能拿到實例,效率低。
兩個懶漢式的區別:加不加 sybchronized。
雙重檢查鎖、volatile(常用)
public class Singleton4 {
private Singleton4(){
}
private volatile static Singleton4 instance = null;
private static Singleton4 getInstance(){
if (instance == null){ //1
synchronized (Singleton4.class){
if (instance == null){ //2
instance = new Singleton4();
}
}
}
return instance;
}
}
volatile 關鍵字保證了內存可見性,所有線程都會去主存中取數據而不是在線程的緩存中取,保證了數據的更新能實時地對任何線程可見。
假如有兩個線程同時到達了1,它們都去創建實例,這時候如果沒有第二次判斷,就會多次創建實例了。二次判斷保證了多線程下只創建一個實例。
靜態內部私有類(常用)
public class Singleton5 {
private Singleton5(){
}
private static class Singleton5Holder{
private static Singleton5 instance = new Singleton5();
}
public static Singleton5 getInstance(){
return Singleton5Holder.instance;
}
}
靜態內部類不會隨着外部類的加載而加載 ,只有靜態內部類的靜態成員被調用時纔會進行加載(實例化)。同時,虛擬機會保證一個類的構造器方法在多線程環境中被正確地加載,同步,如果多個線程同時去初始化一個類,那麼只有一個線程去執行這個類的。所以這種方法支持多併發,效率高。
枚舉
public enum Singleton6 {
INSTANCE;
}
外部調用由原來的Singleton.getInstance變成了Singleton.INSTANCE了。