一。單例設計模式(SINGLETON)概念
在整個應用生命週期內只存在一個例項,叫做單例,是廣泛使用的設計模式。優點是,避免多次建立例項,減少記憶體開銷。
二。面試中常問的問題
來手寫個單例設計模式:
public class Singleton { private static Singleton instance; private Singleton() { } public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; }}
請問這種方式有什麼壞處?
答:這個是懶漢式,存線上程安全問題,餓漢式我就不寫了。
那怎麼修復呢?
public class Singleton { private static Singleton instance; private Singleton() { } synchronized public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; }}
執行緒是安全了,請問有什麼缺點,有什麼更好的方式嗎?
答:確實代價太大了,我來再想想怎麼最佳化,你應該若有所思的樣子去思考。
public class Singleton { private static Singleton instance; private Singleton() { } public static Singleton getInstance() { if (instance == null) { synchronized (Singleton。class) { if (instance == null) { instance = new Singleton(); } } } return instance; }}
面試官點點頭,還能最佳化嗎?
答:咱思考下,再最佳化下。
public class Singleton { private volatile static Singleton instance; private Singleton() { } public static Singleton getInstance() { if (instance == null) { synchronized (Singleton。class) { if (instance == null) { instance = new Singleton(); } } } return instance; }}
為什麼這麼設計呢?
答:在instance = new Singleton()這一行,jvm會做如下操作:
給例項分配記憶體;
透過建構函式,成員變數初始化;
將instance指向分配的記憶體空間。但是他們順序有可能被打亂,也就是指令重排。在JDK5之後,使用volatile關鍵字,可以防止指令重排,保證了instance對所有的執行緒可見性。似乎一切在咱的掌握之中,面試官有可能還會問,還有其他的方式來保證執行緒安全嗎?前提是不使用synchronized關鍵字。
public
class
Singleton
{
private
Singleton
() {
}
public
static
Singleton
getInstance
() {
return
SingletonInner
。
instance
;
}
private
static
class
SingletonInner
{
static
final
Singleton
instance
=
new
Singleton
();
}
}
答:透過靜態記憶體類的方式,在初次載入類時,類的靜態屬性進行初始化, 並且JVM虛擬會保證併發訪問, 不會出現併發問題。由於靜態變數只初始化一次, 絕對可以保證單例。還有別的方式嗎?答:透過列舉。每個列舉常量,代表一個常量例項。且列舉例項不能被克隆,所以不能透過反射產生例項。而且列舉的建立,JVM會保證執行緒安全的,不存線上程安全問題。