亮點面試題&&實現Singleton(辛格爾頓)模式-JAVA版本

來源:互聯網
上載者:User

標籤:

稱號:設計一個類。我們只能產生這個類的一個執行個體。(來自《劍指Offer》)
解析:僅僅能生產一個執行個體的類是實現Singleton(單例)模式的類型。因為設計模式在物件導向程式設計中起著舉足輕重的作業,在面試過程中非常多公司都喜歡問一些與設計模式相關的問題。

在經常使用的模式中,Singleton是唯一一個可以用短短几十行代碼完整實現的模式。

因此,寫一個Singleton的類型是一個非經常見的面試題。


下面我們給出幾種解法。供大家參考。


*不好的解法一:僅僅適用於單線程環境。


因為要求僅僅能產生一個執行個體。因此我們必須把建構函式設為私人函數以禁止他人建立執行個體。我們能夠定義一個靜態執行個體,在須要的時候建立該執行個體。基於這個思路的實現:
public class Singleton1{
private Singleton1(){
}
private final static Singleton1 instance = null;
public static Singleton1 getInstance(){
if(instance == null)
instance = new Singleton1();
return instance;
}
}
上述代碼在Singleton1的靜態屬性Instance中,僅僅有在instance為null的時候才建立一個執行個體以避免反覆建立。同一時候。我們把建構函式定義為私人函數,這樣就能確保僅僅建立一個執行個體。




*不好的解法二:儘管在多線程環境中能工作但效率不高
解法一中的代碼在單線程的時候工作正常。但在多線程的情況下就有問題了。設想假設兩個線程同一時候執行到推斷instance是否為null的if語句。而且instance的確沒有建立時,那麼兩個線程都會建立一個執行個體,此時類型Singleton1就不再滿足單例模式的要求了。

為了保證在多線程環境下我們還是僅僅能得到類型的一個執行個體,須要加上一個同步鎖。把Singleton1稍做改動得到了例如以下代碼:
public class Singleton2 {
   private static Singleton2 instance = null;
   private Singleton2() { }


   public static synchronized Singleton2 getInstance() {
      if(instance == null) {
         instance = new Singleton2();
      }
      return instance;
   }
}
我們還是如果有兩個線程同一時候想建立一個執行個體。因為在一個時刻僅僅有一個線程能得到同步鎖。當第一個線程加上鎖時,第二個線程僅僅能等待。當第一個線程發現執行個體還沒有建立時,它建立出一個執行個體。接著第一個線程釋放同步鎖,此時第二個線程能夠加上同步鎖,並執行接下來的代碼。這個時候因為執行個體已經被第一個線程建立出來了,第二個線程就不會反覆建立執行個體了,這樣就保證了我們在多線程環境中也僅僅能得到一個執行個體。
可是類型Singleton2還不是非常完美。我們每次通過屬性Instance得到Singleton2的執行個體,都會試圖加上一個同步鎖,而加鎖是一個非常耗時的操作。在沒有必要的時候我們應該盡量避免。
**可行的解法一:加同步鎖前後兩次推斷執行個體是否已存在
我們僅僅是在執行個體還沒有建立之前須要加鎖操作,以保證僅僅有一個線程建立執行個體。而當執行個體已經建立之後,我們已經不須要再加鎖操作了。所以我們改進例如以下:
public class Singleton3 {
   private static Singleton3 instance = null;
   private Singleton3() { }
   public static Singleton3 getInstance() {
      if(instance == null) {
         synchronzied(Singleton3.class) {
            Singleton3 temp = instance;
            if(temp == null) {
               temp = new Singleton3();
               instance = temp
            }
         }
      }
      return instance;
   }
}
因為指令重排序問題,所以不能夠直接寫成以下這樣:
public class Singleton3 {
   private static Singleton3 instance = null;
   private Singleton3() { }
   public static Singleton3 getInstance() {
      if(instance == null) {
         synchronzied(Singleton3.class) {
            if(instance == null) {
               instance = new Singleton3();
            }
         }
      }
      return instance;
   }
}
可是假設instance執行個體變數用volatile修飾就能夠了,volatile修飾的話就能夠確保instance = new Singleton();相應的指令不會重排序,例如以下的單例代碼也是安全執行緒的:
public class Singleton3 {
   private static volatile Singleton3 instance = null;
   private Singleton3() { }
   public static Singleton3 getInstance() {
      if(instance == null) {
         synchronzied(Singleton3.class) {
            if(instance == null) {
               instance = new Singleton3();
            }
         }
      }
      return instance;
   }
}
Singleton3用加鎖機制來確保在多線程環境下僅僅建立一個執行個體,而且用倆個if推斷來提高效率。

這種代碼實現起來比較複雜,easy出錯,我們還有更優秀的解法。


**強烈推薦的解法二:藉助內部類
這樣的方法屬於懶漢式單例,由於Java機制規定,內部類SingletonHolder僅僅有在getInstance()方法第一次調用的時候才會被載入(實現了lazy)。並且其載入過程是線性安全的。內部類載入的時候執行個體化一次instance。
public class Singleton {


   private Singleton() { }  
    private static class SingletonHolder {
      private final static Singleton INSTANCE = new Singleton();
   } 
    public static Singleton getInstance() {
      return SingletonHolder.INSTANCE;
   }
}
 


 

著作權聲明:本文部落格原創文章,部落格,未經同意,不得轉載。

亮點面試題&&實現Singleton(辛格爾頓)模式-JAVA版本

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.