單例模式 線程安全+序列化處理

單例模式寫法分享

雙重判定鎖寫法

public class Singleton implements Serializable {
    private static volatile Singleton singleton = null;
 
	private Singleton(){
		if (singleton != null) {
			throw new Exception(“該實例已生成,禁止被反射調用生成”)
		}
}
 
    public static Singleton getSingleton(){
        if(singleton == null){
            synchronized (Singleton.class){
                if(singleton == null){
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
}

     private Object readResolve() throws ObjectStreamException {
       return singleton;
     }

}

靜態內部類寫法:

public class Singleton {
    private transient static class Holder {
        private static Singleton singleton = new Singleton();
    }
 
    private Singleton(){
    	if (singleton != null) {
			throw new Exception(“該實例已生成,禁止被反射調用生成”)
		}
    }
 
    public static Singleton getSingleton(){
        return Holder.singleton;
    }
}

上述兩寫法缺點:都需要額外的工作(Serializable、transient、readResolve())來實現序列化,否則每次反序列化一個序列化的對象實例時都會創建一個新的實例

枚舉寫法 Joshua Bloch的推薦:

public enum Singleton {
    INSTANCE;
    private String name;
    public String getName(){
        return name;
    }
    public void setName(String name){
        this.name = name;
    }
}

Effective Java推薦儘可能地使用枚舉來實現單例。

Spring,單例註冊表:

public abstract class AbstractBeanFactory implements ConfigurableBeanFactory{  
       /** 
        * 充當了Bean實例的緩存,實現方式和單例註冊表相同 
        */  
       private final Map singletonCache=new HashMap();  
       public Object getBean(String name)throws BeansException{  
           return getBean(name,null,null);  
       }  
    ...  
       public Object getBean(String name,Class requiredType,Object[] args)throws BeansException{  
          //對傳入的Bean name稍做處理,防止傳入的Bean name名有非法字符(或則做轉碼)  
          String beanName=transformedBeanName(name);  
          Object bean=null;  
          //手工檢測單例註冊表  
          Object sharedInstance=null;  
          //使用了代碼鎖定同步塊,原理和同步方法相似,但是這種寫法效率更高  
          synchronized(this.singletonCache){  
             sharedInstance=this.singletonCache.get(beanName);  
           }  
          if(sharedInstance!=null){  
             ...  
             //返回合適的緩存Bean實例  
             bean=getObjectForSharedInstance(name,sharedInstance);  
          }else{  
            ...  
            //取得Bean的定義  
            RootBeanDefinition mergedBeanDefinition=getMergedBeanDefinition(beanName,false);  
             ...  
            //根據Bean定義判斷,此判斷依據通常來自於組件配置文件的單例屬性開關  
            //<bean id="date" class="java.util.Date" scope="singleton"/>  
            //如果是單例,做如下處理  
            if(mergedBeanDefinition.isSingleton()){  
               synchronized(this.singletonCache){  
                //再次檢測單例註冊表  
                 sharedInstance=this.singletonCache.get(beanName);  
                 if(sharedInstance==null){  
                    ...  
                   try {  
                      //真正創建Bean實例  
                      sharedInstance=createBean(beanName,mergedBeanDefinition,args);  
                      //向單例註冊表註冊Bean實例  
                       addSingleton(beanName,sharedInstance);  
                   }catch (Exception ex) {  
                      ...  
                   }finally{  
                      ...  
                  }  
                 }  
               }  
              bean=getObjectForSharedInstance(name,sharedInstance);  
            }  
           //如果是非單例,即prototpye,每次都要新創建一個Bean實例  
           //<bean id="date" class="java.util.Date" scope="prototype"/>  
           else{  
              bean=createBean(beanName,mergedBeanDefinition,args);  
           }  
    }  
       return bean;  
    }  
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章