1. 程式人生 > >我理解的單例設計模式

我理解的單例設計模式

單例模式 singleton

單例模式我們在開發中經常用到,但是我們可能熟知一種單例模式,但是單例模式也有好多種,現在就對幾種單例模式做個比較,明白其中的優缺點:

  1. 單例代碼:“餓漢式”,也就是當類加載進來的時候就創建實例,但是這種方式比較消耗資源。(單例模式的第一個版本)
public class Singleton{
     private static Singleton single=new Singleton();

     private Singleton(){
          System.out.println("生成一個Singleton實例");
     }

     public static Singleton getInstance(){
          return single;
     }

}

2.測試代碼

public class SingletonTest{

     public static void main(String[] args){
         System.out.println("Start...");
         Singleton single1=Singleton.getInstance();
         Singleton single2=Singleton.getInstance();
         if(single1==single2){
             System.out.println("obj1 和 obj2 是相同的實例。"); 
         }else{
             System.out.println("obj1 和 obj2 是不同的實例。");
         }
         System.out.println("End...");

     }
}

3.測試結果

Start...
生成一個Singleton實例
obj1 和 obj2 是相同的實例。
End...

  1. 不是嚴格的Singleton模式的例子:“懶漢式”:單線程下可以,多線程下存在線程安全問題。(單例模式的第二個版本), 這段代碼如果是在單線程中是沒有什麽問題的,但是因為沒有鎖的機制,在多線程中就會有問題,當同一時間有兩個或者兩個以上線程進入getInstance()方法時,因為剛開始single都是null , 幾個線程都同時滿足if(single==null) 這個條件,就會同時new Singleton() 這個對象
public class Singleton{
     private static Singleton single=null;
     private Singleton(){
         System.out.println("生成一個Singleton實例"); 
     }
     public static Singleton getInstance(){
          if(single==null){
              single=new Singleton(); 
          }
          return single;
     }
}

5.不是嚴格單例模式測試代碼

public class SingletonThread implements Runnable {
     private Set<Singleton> set=new HashSet<Singleton>();
     @Override
     public void run() {
          Singleton single=Singleton.getInstance();
          set.add(single);
          System.out.println("Set的大小為:"+set.size()+","+set);
     }
}

測試類Main方法

public class SingleTest {
     public static void main(String[] args) {
          SingletonThread t=new SingletonThread();
          new Thread(t).start();
          new Thread(t).start();
          new Thread(t).start();
          new Thread(t).start();
          new Thread(t).start();
     }
}

6.測試結果:會看到會有多個“生成一個Singleton實例”,說明調用了5次 new Singleton()方法。
技術分享圖片

7.如果使用第一種方法的話:只會有一個“生成一個Singleton實例 ”,說明只調用了一次 new Singleton() 方法。

技術分享圖片

8.為了解決第二種多線程安全問題,采用對函數進行同步的方式,但是也比較浪費資源,因為每次都要進行同步檢查,而實際真正需要檢查的只是第一次。(單例模式的第三個版本)

public class Singleton{
     private static Singleton single=null;
     private Singleton(){
         System.out.println("生成一個Singleton實例");
     }
     public static synchronized Singleton getInstance(){
          if(single==null){
              single=new Singleton();
          }
          return single;
     }
}

運行結果:
技術分享圖片

9.(單例模式的第四個版本)既解決了“懶漢式”多線程的安全問題,又解決了浪費資源的現象。

public class Singleton{
     private static Singleton single;
     private Singleton(){
        System.out.println("生成一個Singleton實例");
     }
     public static Singleton getInstance(){
        if(single==null){
          synchronized(Singleton.class) {
              if(single==null) {
              single=new Singleton();
              }
          }
        }
        return single;
   }
}

運行結果:

技術分享圖片

10.單例模式優缺點總結:

優點:客戶端使用單例模式的實例的時候,只需要調用一個單一的方法就可以得到一個唯一的實例,有利於節省資源。
缺點:首先單例模式很難實現實例化,這就導致采用單例模式的類很難被持久化,當然也很難通過網絡進行傳輸;其次,由於單例采用靜態方法,無法再繼承結構中使用。

我理解的單例設計模式