一、單例模式(singleton pattern)
單例模式只涉及到乙個單一的類,該類負責建立自己的物件,同時確保只有單個物件被建立。並且提供了訪問其唯一物件的方式,可以直接訪問,不需要在外部例項化該類的物件。
1、單例模式可總結為以下三點:
1)構造方法使用private私有化(保證外部無法new出例項物件);
2)內部自己建立自己的唯一例項物件;
3)對外部提供方法直接訪問唯一例項物件(使用static保證外部可通過類名訪問)。
2、**實現:
單例模式實現方式有兩種:餓漢式和懶漢式。
1)餓漢式:不管singleton類物件是否使用,只要類載入就產生乙個例項物件。
class singleton
//對外部提供訪問唯一物件的方法
public static singleton getinstance()
}
2)懶漢式:當第一次使用singleton類物件的時候,才執行例項化操作。
/*非完美版本*/
class singleton
public static singleton getinstance()
return instance;
}}
二、單例模式存在的問題:
1、懶漢式單例模式多執行緒下不安全
為什麼說不安全呢?舉個簡單的例子,假設有兩個執行緒都需要使用這個物件,執行緒 a 先執行語句 if (instance == null) 得到結果為 true,但還沒有來得及執行語句instance = new singleton();此時 cpu 切換去執行執行緒 b,這時候由於執行緒a並沒有執行new操作,所以執行緒 b 在執行語句 if (instance == null) 時又得到結果為true,緊接著執行緒b建立了該類的例項物件,當 cpu 重新回到執行緒a去執行的時候,又建立了乙個類的例項物件,也就是說建立的物件不是唯一的,這就是懶漢式多執行緒不安全的表現。
如何解決這個問題?
方法一:使用執行緒安全關鍵字synchronized
/*使用synchronized,保證執行緒在建立物件的時候讓其他執行緒阻塞*/
//寫法一
public static synchronized singleton getinstance()
return instance;
}//另外一種寫法,本質上沒有區別
public static singleton getinstance()
}return instance;
}
方法二:雙重判空操作實現單例模式(重要)
多執行緒不安全是由於第一次建立物件時,恰好發生了執行緒切換,這種情況在後續的呼叫中不會再次出現,因此可在synchronized語句前增加一次判空操作,以解決方法一中存在的不足。
public static singleton getinstance()}}
return instance;
}
2、指令重排序
什麼是指令重排序?jvm為了提高程式執行效率,在不影響單執行緒程式執行結果的前提下,對指令進行優化。 也就是說這種優化,在多執行緒下,就可能出現問題。以上面所寫雙重判空操作實現的單例模式為例:
問題就出在instance = new singleton(); 這句話的執行過程可以分為三步:
1)分配記憶體空間。
2)通過構造方法初始化。
3)instance引用該記憶體空間。
如果發生指令重排,那麼執行順序可能發生變化:
1)分配記憶體空間。
2)instance引用該記憶體空間。
3)通過構造方法初始化。
雖然2和3的執行順序發生了變化,但對單執行緒執行結果沒有影響,而在多執行緒情況下就會出現問題:可能會返回乙個空的instance,而我們卻認為是正常執行的。
解決方法:通過 volatile 避免指令重排序
volatile關鍵字的作用: 1)可以保證變數的可見性; 2)阻止發生指令重排序。
/*完美版本*/
class singleton
public static singleton getinstance()}}
return instance;
}
三、單例模式的其他實現方法
1、使用靜態內部類實現單例模式
我們知道,靜態內部類不依靠外部類的存在而存在,因此我們可以這樣設計:
1)在這個靜態內部類初始化的時候,生成外部類的物件。
2)然後在呼叫 getterinstance 方法時返回該外部類物件。
**實現如下:
class singleton
//私有構造方法
private singleton()
//提供getter方法訪問instance
public static singleton getterinstance()
//測試
public void print()
}public class test
}
2、列舉(enum)實現單例模式
使用列舉實現單例的方法很簡單,而且 enum 類的建立本身執行緒就是安全的,在這這一點上和靜態內部類很相似。
public class singletontest
public static void main(string args)
}
單例模式總結
三種實現單例模式的對比 1.volatile關鍵字不但可以防止指令重排,也可以保證執行緒訪問的變數值是 主記憶體中的最新值 有關volatile的詳細原理,我在以後的漫畫中會專門講解。2.使用列舉實現的單例模式,不但可以防止利用反射強行構建單例物件 可以而且在列舉類物件被 反序列化 的時候,保證反序...
單例模式總結
單例模式的使用有乙個必要的條件,在乙個系統要求乙個類只有乙個例項時才應當使用單例模式。在懶漢式單例的時候為什麼要進行執行緒的控制呢?package 單例模式.懶漢模式 public class lazysingleton synchronized public lazysingleton getin...
單例模式總結
單例模式,最常見的有兩種單例模式,餓漢式和懶漢式,如下 餓漢式 public class singletonhungry public singletonhungry getinstance 懶漢式 public class singletonlazy 靜態工廠方法 public static si...