什么是單例?
確保一個類只有一個實例,并提供一個全局訪問點。
應用
線程池,緩存,數據庫等,這些類只需要一個實例,如果多個實例會造成異常的情況。
實現
懶漢式簡單的實現
public class Singleton {
private static Singleton singleton;
private Singleton() {
}
public static Singleton getInstance() {
if (singleton == null) {//位置一
singleton = new Singleton();
}
return singleton;
}
}
簡單的實現在遇到多線程的時候就會出現問題。比如第一次創建singleton時,線程1執行位置一,這個時候線程2也要獲取一個singeton,它也執行到了位置一,然后線程1向下執行獲取到了singleton,然后線程2向下執行,singleton又重新被實例化,線程2又獲取到一個新的Singeton的實例。
- 應對多線程,那就用synchronized方法吧,重新寫getInstance方法
public static synchronized Singleton getInstance(){
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
使用synchronized方法修飾之后,避免了多線程的問題,那我們看看有沒有其他的問題?
synchronized 會降低性能,每次獲取實例的時候多要判斷getInstance方法有沒有執行完,但是我們只需要在第一次實例化singleton時需要synchronized。
- 雙重檢查加鎖,在getInstance中減少synchronized,提高性能
private volatile static Singleton singleton4;//volatile關鍵字確保:當singleton變量被實例化成Singleton實例時,多個線程正確地處理singleton變量
public static Singleton getInstance(){
if (singleton == null) {//檢查實例,如果不存在,進去同步區
synchronized (Singleton.class) {//只有第一次才徹底執行這里的代碼
if (singleton == null) {//再次判空,
singleton = new Singleton();
}
}
}
return singleton;
}
以上都是懶漢式的單例,也就是延遲加載,用到Singeton實例的時候才創建一個實例。下面看看餓漢式的單例模式
private static Singleton singleton3 = new Singleton();
public static Singleton getInstance(){
return singleton;
}
還有一種內部類的實現方式,比較常用
private static class SingletonHolder{
private static Singleton instance = new Singleton();
}
public static Singleton getInstance(){
return SingletonHolder.instance;
}
結束語
- 單例模式確保程序中一個類最多只有一個實例。
- 單例模式提供一個全局訪問點。
- 私有的構造器,一個靜態方法和一個靜態變量。