線程安全的單例模式

1. 全局變量的缺點:數據庫

必須在程序一開始就建立好對象,若是程序在此次的執行過程當中又一直沒用到它,就很是耗費資源。緩存

 

2. 經典的單例模式實現:安全

Java代碼
public class Singleton {    
      //用一個靜態變量來記錄Singleton類的惟一實例   
      private static Singleton uniqueInstance;
      private Singleton() {}   
           
      //注意這個方法也是靜態的   
      public static Singleton getInstance() {    
           if(uniqueInstance == null) {   
             uniqueInstance = new Singleton();   
           }   
           return uniqueInstance;   
      }   
}  

    單例常被用來管理共享的資源,例如數據庫鏈接、線程池、緩存、註冊表。多線程

    單例模式確保一個類只有一個實例,並提供一個全局訪問點。性能

    這個模式的問題:在多線程時,並不能保證這個類只被實例化一次。優化

 

3. 處理多線程:spa

Java代碼
public class Singleton {    
    //用一個靜態變量來記錄Singleton類的惟一實例   
    private static Singleton uniqueInstance;   
    
    private Singleton() {}   
           
    //注意這個方法也是靜態的   
    public static synchronized Singleton getInstance() {    
        if(uniqueInstance == null) {   
             uniqueInstance = new Singleton();   
         }   
         return uniqueInstance;   
    }   
}  

 

   經過增長synchronized關鍵字到getInstance()方法中,迫使每一個線程在進入方法以前,要先等別的線程離開該方法。也就是說,不會有兩個線程能夠同時進入這個方法。線程

 

   這種方法存在的問題:只有第一次執行此方法時,才真正須要同步。換句話說,一旦設置好uniqueInstance變量,就再也不須要同步這個方法了。以後每次調用這個方法,同步都是一種浪費。code

 

4.改善多線程對象

 

4.1 若是getInstance()的性能對應用程序不是很關鍵,就不用優化了

4.2 使用急切建立實例,而不用延遲實例化的作法

Java代碼
public class Singleton {
    private static Singleton uniqueInstance = new Singleton();
    private Singleton() {}
    public static Singleton getInstance() {    
         return uniqueInstance;   
    }
}

   標紅的語句在靜態初始化器(static initializer)中建立單例,這保證了線程安全。

   利用這個作法,JVM在加載這個類時立刻建立此惟一的單件實例。JVM保證任何線程訪問uniqueInstance靜態變量以前,必定先建立些實例。

 

   4.3 用「雙重檢查加鎖」,在getInstance()中減小使用同步

    首先檢查實例是否已經建立,若是還沒有建立,才進行同步。這樣一來,只有第一次會同步,這正是咱們想要的。

Java代碼

 

public class Singleton {
    private volatile static Singleton uniqueInstance;
    private Singleton() {}
    public static Singleton getInstance() {    
    if(uniqueInstance == null) {//(1)
//只有第一次才完全執行這裏的代碼 
 synchronized() { //再檢查一次 
          if(uniqueInstance == null) uniqueInstance = new Singleton(); } } return uniqueInstance; } } 

   在最開始若是有一、二、3個線程走到了(1)處,假設1進入了同步塊,二、3等待。1實例化後,2進入同步塊,發現uniqueInstance已經不爲空,跳出同步塊。接着3進入,又跳出同步塊。

    volatile關鍵字確保:當uniqueInstance變量被初始化成Singleton實例時,多個線程正確地uniqueInstance變量。若是性能是你關心的重點,那麼這個作法能夠幫你大大地減小getInstance()的時間耗費。

相關文章
相關標籤/搜索