一,什麼是單例模式?
單例模式是一種對象創建型模式,使用單例模式,可以保證爲一個類只生成唯一的實例對象。也就是說,在整個程序空間中,該類只存在一個實例對象。
其實,GoF( Gang of Four,代表意思是 設計模式一書,四個作者,被稱爲四人組)對單例模式的定義是: 保證一個類,只有一個實例存在,同事提供能對該實例加以訪問的全局訪問方法。
二,爲什麼要使用單例模式呢?
在開發中,我們常常有以下需求:
-在多個線程之間,比如servlet 環境,共享同一個資源或者操作同一個對象
-在整個程序中使用全局變量,共享資源。
-在整個系統中,爲了性能的考慮,需要節省對象的創建時間等等
Singleton模式可以保證爲了一個類只生成唯一的實例對象。
三,單例模式實現。
3.1 餓漢式。
public class Singleton {
//餓漢式單例模式
private static final Singleton singleton = new Singleton();
/**
* 私有化構造方法
*/
private Singleton() {
}
/**
* 提供一個全局的靜態方法
* @return
*/
public static Singleton getSingleton() {
return singleton;
}
}
3.2 懶漢式。
public class SingletonLazy {
/**
*
*/
private static SingletonLazy singletonLazy;
/**
* 構造方法實例化
*/
private SingletonLazy() {
}
/**懶漢模式,在不需要的時候並不會去創建實例,只有在真正調用的時候
* 提供給外部的靜態方法纔去實例化
* @return
*/
private static SingletonLazy getInstance(){
if(singletonLazy ==null){
return new SingletonLazy();
}
return singletonLazy;
}
}
3.3 雙重檢查。
public class SingletonCheck {
private volatile static SingletonCheck singletonCheck;
/**
* 構造方法實例化
*/
private SingletonCheck() {
}
/**
*
* 雙重檢查,在多線程的環境下,會出現資源競爭。
* 在 A線程剛進入 if 判斷的時候, B線程 就已經實例化了。這時候 我們需要加上 synchronized (同步),
* 這樣能保證 A線程執行完方法體,B線程 才能執行。
* synchronized 放在 if 裏面 是爲了節省性能,在需要線程同步的地方去做線程同步。 第一重檢查
* 第二重檢查, 當 A,B線程先後進入if 判斷都是null時,都會去 肯定有一個線程阻塞在 if判斷這裏,
* 只有當另一個線程 去實例化完成之後, 另一個線程 纔會去 實例化,但是 之前已經有一個實例化對象了,
* 現在又出現兩次實例化對象,肯定是不符合我們的初衷的,所以在 同步方法內 在做一次檢查,對象是否爲空,
* 這就是雙重檢查
* @return
*/
private static SingletonCheck getInstance(){
if(singletonCheck ==null){
synchronized (SingletonCheck.class) {
if(singletonCheck ==null) {
singletonCheck = new SingletonCheck();
}
}
}
return singletonCheck;
}
}
3.4靜態內部類單例模式。
public class SingletonStatic {
private SingletonStatic(){
}
/**
* 只有第一次調用getInstance方法時,虛擬機才加載 Inner 並初始化instance ,只有一個線程可以獲得對象的初始化鎖,
* 其他線程無法進行初始化,保證對象的唯一性。目前此方式是所有單例模式中最推薦的模式,但具體還是根據項目選擇。
*/
public static SingletonStatic getInstance(){
return Inner.instance;
}
private static class Inner {
private static final SingletonStatic instance = new SingletonStatic();
}
}
3.5 枚舉單例模式
public enum SingletonEnum {
INSTANCE;
/** 默認枚舉實例的創建是線程安全的,並且在任何情況下都是單例
* 枚舉單例模式在《Effective Java》中推薦的單例模式之一。但枚舉實例在日常開發是很少使用的,就是很簡單以導致可讀性較差。
* @return
*/
public static SingletonEnum getInstance() {
return SingletonEnum.INSTANCE;
}
}
推薦:使用 3.4靜態內部類單例模式,直觀,簡潔,同樣是線程安全的