1. 程式人生 > >單例7種寫法

單例7種寫法

轉載出處 :http://www.blogjava.net/kenzhh/archive/2013/03/15/357824.html

第一種(懶漢模式):這種寫法lazy loading很明顯,但是致命的是在多執行緒不能正常工作。

public class Singleton {
        private static Singleton instance;

        private Singleton() {
        }

        public static Singleton getInstance() {
            if (instance == null) {
                instance = new Singleton();
            }
            return instance;
        }
    }

對上面問題修改一下

  private static Class getClass(String classname)      
                                           throws ClassNotFoundException {     
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();     
        
        if(classLoader == null)     
           classLoader = Singleton.class.getClassLoader();     
        
        return (classLoader.loadClass(classname));     
     }     
 }  



第二種(懶漢模式):這種寫法能夠在多執行緒中很好的工作,而且看起來它也具備很好的lazy loading,但是,遺憾的是,效率很低,99%情況下不需要同步。
  public class Singleton {  
      private static Singleton instance;  
      private Singleton (){}
      public static synchronized Singleton getInstance() {  
      if (instance == null) {  
          instance = new Singleton();  
      }  
      return instance;  
      }  
}  
對上面程式碼進行改善
 public class Singleton implements java.io.Serializable {     
     public static Singleton INSTANCE = new Singleton();     
       
     protected Singleton() {     
          
     }     
     private Object readResolve() {     
              return INSTANCE;     
        }    
 }  


第三種(餓漢模式):這種方式基於classloder機制避免了多執行緒的同步問題,不過,instance在類裝載時就例項化,雖然導致類裝載的原因有很多種,在單例模式中大多數都是呼叫getInstance方法,但是也不能確定有其他的方式(或者其他的靜態方法)導致類裝載,這時候初始化instance顯然沒有達到lazy loading的效果。
 public class Singleton {  
     private static Singleton instance = new Singleton();  
     private Singleton (){}
     public static Singleton getInstance() {  
     return instance;  
     }  
 }  

第四種(漢,變種):表面上看起來差別挺大,其實更第三種方式差不多,都是在類初始化即例項化instance。
 public class Singleton {  
      private Singleton instance = null;  
      static {  
      instance = new Singleton();  
      }  
      private Singleton (){}
      public static Singleton getInstance() {  
      return this.instance;  
     }  
 } 

第五種(靜態內部類):

這種方式同樣利用了classloder的機制來保證初始化instance時只有一個執行緒,它跟第三種和第四種方式不同的是(很細微的差別):第三種和第四種方式是隻要Singleton類被裝載了,那麼instance就會被例項化(沒有達到lazy loading效果),而這種方式是Singleton類被裝載了,instance不一定被初始化。因為SingletonHolder類沒有被主動使用,只有顯示通過呼叫getInstance方法時,才會顯示裝載SingletonHolder類,從而例項化instance。想象一下,如果例項化instance很消耗資源,我想讓他延遲載入,另外一方面,我不希望在Singleton類載入時就例項化,因為我不能確保Singleton類還可能在其他的地方被主動使用從而被載入,那麼這個時候例項化instance顯然是不合適的。這個時候,這種方式相比第三和第四種方式就顯得很合理。

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

第六種(列舉):這種方式是Effective Java作者Josh Bloch 提倡的方式,它不僅能避免多執行緒同步問題,而且還能防止反序列化重新建立新的物件,可謂是很堅強的壁壘啊,不過,個人認為由於1.5中才加入enum特性,用這種方式寫不免讓人感覺生疏,在實際工作中,我也很少看見有人這麼寫過。
 public enum Singleton {  
     INSTANCE;  
     public void whateverMethod() {  
     }  
 }  
第七種(雙重校驗鎖):
public class Singleton {    
      private volatile static Singleton singleton;    
      private Singleton (){}     
      public static Singleton getSingleton() {    
      if (singleton == null) {    
          synchronized (Singleton.class) {    
          if (singleton == null) {    
              singleton = new Singleton();    
          }    
         }    
     }    
     return singleton;    
     }    
 } 

不過一般來說,第一種不算單例,第四種和第三種就是一種,如果算的話,第五種也可以分開寫了。所以說,一般單例都是五種寫法。懶漢,惡漢,雙重校驗鎖,列舉和靜態內部類。