反射 序列化 克隆對單例模式的破壞

所謂單例模式就是,某一個類只能有一個實例,實現的核心就是將類的構造函數私有化,只能由該類建立對象,其餘對象就不能調用該類的構造函數,即不能建立對象了。java

如今看一個問題:對象的建立方式有哪幾種? 
四種:new 、克隆、序列化、反射安全

其實上面的說法有點問題,改成:……其餘對象就不能調用該類的構造函數,即不能經過new 來建立對象了。那麼是否還有能夠經過其餘的三種方式建立對象呢,即其餘三種方式會不會破壞單例模式呢?函數

  • 克隆可能對單例模式的破壞spa

    由克隆咱們能夠想到原型模式,原型模式就是經過clone方法實現對象的建立的,clone方式是Object方法,每一個對象都有,那我使用一個單例模式類的對象,調用clone方法,再建立一個新的對象了,那豈不是上面說的單例模式失效了。固然答案是否認,某一個對象直接調用clone方法,會拋出異常,即並不能成功克隆一個對象。調用該方法時,必須實現一個Cloneable 接口。這也就是原型模式的實現方式。還有即若是該類實現了cloneable接口,儘管構造函數是私有的,他也能夠建立一個對象。即clone方法是不會調用構造函數的,他是直接從內存中copy內存區域的。因此單例模式的類是不能夠實現cloneable接口的。線程

  • 序列化可能對單例模式的破壞code

    一是能夠實現數據的持久化;二是能夠對象數據的遠程傳輸。 
    若是過該類implements Serializable,那麼就會在反序列化的過程當中再創一個對象。這個問題的解決辦法就是在反序列化時,指定反序化的對象實例。添加以下方法:對象

private static final long serialVersionUID = -3979059770681747301L;

    private volatile static Singleton singleton;

    private Object readResolve() {
        return singleton;
    }
  • 反射可能對單例模式的破壞

反射是能夠獲取類的構造函數,再加一行 setAccessible(true);就能夠調用私有的構造函數,建立對象了。那麼防止反射破壞Java單例模式的方法就是:當第二次調用構造函數時拋出異常。代碼以下:接口

private volatile static Singleton1 singleton;

    private  static boolean  flag = true;
    private Singleton1 (){
        if(flag){
        flag = false;   
        }else{
            throw new RuntimeException("單例模式險些被破壞,第二個對象未建立成功");
        }

    }

還有一種方式是經過枚舉實現。內存

下面開始正式講單例模式方式: 
最好的就是雙重檢測校檢鎖,不過下面將所有的幾種方式都寫出來。 
一、線程不安全:懶漢: (懶漢就是延遲加載)get

package com.txc.singleton;

import java.io.Serializable;
//線程不安全:懶漢 
public class Singleton2 implements Serializable{

    /**
     * 
     */
    private static final long serialVersionUID = 2857896192197905033L;

    private volatile static Singleton2 singleton;
    private  static boolean  flag = true;
    private Singleton2 (){
        if(flag){
        flag = false;   
        }else{
            throw new RuntimeException("單例模式險些被破壞,第二個對象未建立成功");
        }

    }

    public static Singleton2 getInstance() {  
        if (singleton == null) {  
            singleton = new Singleton2();  
        }  
        return singleton;  
        }  
    private Object readResolve() {
        return singleton;
    }
}

二、線程安全:懶漢:

package com.txc.singleton;

import java.io.Serializable;
//線程不安全:懶漢 
public class Singleton3 implements Serializable{

    /**
     * 
     */
    private static final long serialVersionUID = 2857896192197905033L;

    private volatile static Singleton3 singleton;

    private  static boolean  flag = true;
    private Singleton3 (){
        if(flag){
        flag = false;   
        }else{
            throw new RuntimeException("單例模式險些被破壞,第二個對象未建立成功");
        }

    }

    public static synchronized  Singleton3 getInstance() {  
        if (singleton == null) {  
            singleton = new Singleton3();  
        }  
        return singleton;  
        }  
    private Object readResolve() {
        return singleton;
    }
}

三、餓漢:(非延遲加載)是線程安全的。

package com.txc.singleton;

import java.io.Serializable;
//線程不安全:懶漢 
public class Singleton4 implements Serializable{

    /**
     * 
     */
    private static final long serialVersionUID = 2857896192197905033L;

    private  static Singleton4 singleton= new Singleton4(); 

   private  static boolean  flag = true;
    private Singleton4 (){
        if(flag){
        flag = false;   
        }else{
            throw new RuntimeException("單例模式險些被破壞,第二個對象未建立成功");
        }

    }

    public static  Singleton4 getInstance() {  
        return singleton;  
    }  
    private Object readResolve() {
        return singleton;
    }
}

四、枚舉

public enum Singleton {  
    INSTANCE;  

}

五、雙重校檢鎖

package com.txc.singleton;

import java.io.Serializable;

public class Singleton1 implements Serializable{

    /**
     * 
     */
    private static final long serialVersionUID = -3979059770681747301L;

    private volatile static Singleton1 singleton;


    private  static boolean  flag = true;
    private Singleton1 (){
        if(flag){
        flag = false;   
        }else{
            throw new RuntimeException("單例模式險些被破壞,第二個對象未建立成功");
        }

    }

    public static Singleton1 getSingleton() {
        if (singleton == null) {
            synchronized (Singleton1.class) {
                if (singleton == null) {
                    singleton = new Singleton1();
                }
            }
        }
        return singleton;
    }

    private Object readResolve() {
        return singleton;
    }

}

若有錯誤,請指出。

相關文章
相關標籤/搜索