單例模式總結

2021-09-19 10:56:22 字數 3029 閱讀 1093

一、單例模式(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...