單例模式(Singleton Pattern)
阿新 • • 發佈:2022-05-09
單例模式(Singleton Pattern)
定義
確保一個類只有一個例項,並提供一個全域性訪問點。
類圖
懶漢式
所謂的懶漢式就是延遲物件例項化
程式碼
public class Singleton { private static Singleton singleton; private Singleton(){ System.out.println("我是單例模式獨一無二的物件"); }; //物件只有在呼叫了該方法後才進行例項化 public static Singleton getInstance() { if(singleton==null){ singleton = new Singleton(); } return singleton; } }
單執行緒測試
public class SingletonTest {
public static void main(String[] args) {
Singleton singleton =Singleton.getInstance();
singleton = Singleton.getInstance();
singleton = Singleton.getInstance();
singleton = Singleton.getInstance();
}
}
多執行緒測試
public class SingletonTest { public static void main(String[] args) { new Thread(){ @Override public void run() { Singleton singleton =Singleton.getInstance(); } }.start(); new Thread(){ @Override public void run() { Singleton singleton =Singleton.getInstance(); } }.start(); new Thread(){ @Override public void run() { Singleton singleton =Singleton.getInstance(); } }.start(); new Thread(){ @Override public void run() { Singleton singleton =Singleton.getInstance(); } }.start(); new Thread(){ @Override public void run() { Singleton singleton =Singleton.getInstance(); } }.start(); } }
測試結果:
出現結果分析
簡單改進
//修改getInstance()方法,給它加synchronized 關鍵字
public synchronized static Singleton getInstance() {
if(singleton==null){
singleton = new Singleton();
}
return singleton;
}
但這樣子真的好嘛?仔細想想,好像確實對效能的影響很大,因為我們只在第一次執行這個方法時,才真正需要同步,換句話說,一旦設定好singleton變數,就不再需要同步這個方法了,之後呼叫這個方法,同步都是一種累贅。
改善多執行緒的方法
-
如果getInstance()的效能對應用程式不是很關鍵,那就不需要改了!
同步getInstance()的方法既簡單又有效。但你必須知道,同步一個方法可能造成程式執行效率下降100倍。應此,如果將getInstance()的程式使用在頻繁執行的地方,你可能就得重新考慮了! -
使用“急切”(餓漢式)建立例項,而不用延遲例項化(懶漢式)的做法。
如果程式總是建立並使用單例例項,或者在建立和執行時方面的負擔不太繁重,可以使用此方法
public class Singleton {
private static Singleton singleton =new Singleton();
//在靜態初始化器中建立單例。這段程式碼保證了執行緒安全。
private Singleton(){
System.out.println("我是單例模式獨一無二的物件");
};
public static Singleton getInstance() {
return singleton;//已經有例項了,直接使用它
}
}
-
用“雙重檢索加鎖”,在getInstance()中減少使用同步
如果效能是你關注的重點,那麼這個做法可以幫你大大減少getInstance()的時間耗費。
public class Singleton {
private volatile static Singleton singleton;
private Singleton(){
System.out.println("我是單例模式獨一無二的物件");
};
public static Singleton getInstance() {
if(singleton==null){//檢查是否已經建立
synchronized(singleton){//未建立,則進入同步
if(singleton==null){//再檢查一次,如果仍是null,才建立例項
singleton = new Singleton();
}
}
}
return singleton;
}
}
補充:
volatile關鍵詞確保singleton變數被初始化成Singleton例項時,多執行緒正確地處理singleton變數
總結
懶漢式:延遲了例項化,在單執行緒模式下,能達到單例模式的效果,但在多執行緒環境時,就會出現意想不到的bug,簡單的在getInstance()方法上加synchronized,會降低多執行緒的執行效率,可以利用“雙重檢索加鎖”的方法,提高效率
餓漢式:在靜態初始化器中建立單例,如果程式總是建立並使用單例例項,或者在建立和執行時方面的負擔不太繁重,可以使用此方法,它將不再使用延遲例項化的方法建立單例,依賴JVM在載入這個類時,馬上建立此唯一單例,保證在任何執行緒訪問是singleton變數時,一定先建立此例項!