轉發自:http://blog.csdn.net/ligang7560/article/details/50890282 單例模式的多種實現方式 我們都知道單例模式有幾種常用的寫法: 餓漢模式 懶漢模式 雙重校驗鎖 靜態內部類 靜態代碼塊 我們來看一下這幾種模式在多線程的場景中,能否保持單例 1.餓
轉發自:http://blog.csdn.net/ligang7560/article/details/50890282
單例模式的多種實現方式
我們都知道單例模式有幾種常用的寫法:
- 餓漢模式
- 懶漢模式
- 雙重校驗鎖
- 靜態內部類
- 靜態代碼塊
我們來看一下這幾種模式在多線程的場景中,能否保持單例
1.餓漢模式
public class HungrySingleton {
//立即載入模式
private static HungrySingleton hungrySingleton = new HungrySingleton();
private HungrySingleton(){}
public static HungrySingleton getInstance(){
return hungrySingleton;
}
}
接下來我們寫一個線程類,再寫一個測試類,來看下餓漢模式在多線程下的表現如何:
運行測試類結果如下:
546862187
546862187
546862187
這說明餓漢模式是線程安全,在多線程的情況下,也能夠保持單例.
2.懶漢模式
public class LazySingleton {
private static LazySingleton lazySingleton;
private LazySingleton() {}
public static LazySingleton getInstance(){
if(lazySingleton!=null){
}else{
lazySingleton = new LazySingleton();
}
return lazySingleton;
}
}
同樣的我們來寫一個線程類,寫一個測試類;
運行結果:
2030251396
546862187
2030251396
我們看到對象返回的哈希值不一致了,這就說明他們已經不是同一個對象實例了,也就是說這種寫法是線程不安全的,那麼我們對它進行如下的改造:
public class LazySingleton {
private static LazySingleton lazySingleton;
private LazySingleton() {}
//整個方法加同步,效率低
synchronized public static LazySingleton getInstance(){
if(lazySingleton!=null){
}else{
lazySingleton = new LazySingleton();
}
return lazySingleton;
}
}
我們給整個getInstance方法添加了個synchronized關鍵字,才保證多線程的情況下也能保持單例,我們再運行一下測試類:
1638084561
1638084561
1638084561
這時我們看見已經沒有問題了,就是說寫法是正確的,但是這種寫法導致所以併發的線程獲取實例時都是排隊進行的,那麼就會導致性能低下,接下來我們嘗試另外一種寫法,就是我們的第三種寫法:雙重校驗鎖.
3. 雙重校驗鎖
public class LazySingleton {
private static LazySingleton lazySingleton;
private LazySingleton() {}
public static LazySingleton getInstance(){
if(lazySingleton!=null){
}else{
synchronized (LazySingleton.class){
if(lazySingleton==null){
lazySingleton = new LazySingleton();
}
}
}
return lazySingleton;
}
}
我們將排隊進行的範圍進行縮小,同時採用校驗兩次為空的方法,來保證單例模式的正確性,接下來我們來看一下測試結果:
2030251396
2030251396
2030251396
OK,沒有問題.
4.靜態內部類
public class StaticInnerClassSingleton {
//通過寫一個靜態的內部類來創建實例
private static class SingletonHandle{
private static StaticInnerClassSingleton singleton = new StaticInnerClassSingleton();
}
private StaticInnerClassSingleton(){}
public static StaticInnerClassSingleton getInstance(){
return SingletonHandle.singleton;
}
}
測試類和上面的都差不多,我就不貼圖片了,直接看測試結果:
1523917841
1523917841
1523917841
沒有問題,這種方式也是線程安全的,接下來我們看最後一種方式
5.靜態代碼塊
public class StaticSingleton {
private static StaticSingleton staticSingleton=null;
private StaticSingleton(){};
static {
//通過靜態代碼塊的執行,來獲取實例
staticSingleton = new StaticSingleton();
}
public static StaticSingleton getInstance(){
return staticSingleton;
}
}
不廢話了,直接看測試結果:
2030251396
2030251396
2030251396
沒有問題,那麼以上我們就介紹了5中關於多線程中單例模式的寫法,其中呢就懶漢模式的一般寫法容易造成錯誤,其他的寫法都是線程安全的,文章中的代碼我已經上傳到github了,有需要的同學可以下載下來自己試試.
https://github.com/JokerLigang/Singleton.git