JAVA 7個單例模式方法

1.餓漢式

 餓漢式可以保證多線程下唯一的實例,getInstance性能也比較高,但是無法進行懶加載。

/**
*    餓漢式可以保證多線程下唯一的實例,getInstance性能也比較高,但是無法進行懶加載。
*/
public class Singleton1{

    private static Singleton1 instance = new Singleton1();

    //私有化構造函數,防止被實例化
    private Singleton1(){}

    public static Singleton1 getInstance(){
        return instance;
    }
}

2.懶漢式

懶漢式雖然實現單例的懶加載,但是在多線程下不安全的。因爲線程1判斷null == instance爲true時,還沒有* 實例化instance,切換到了線程2運行,線程2判斷null == instance也爲true。就會實例化多次

/**
* 懶漢式雖然實現單例的懶加載,但是在多線程下不安全的。因爲線程1判斷null == instance爲true時,還沒有* 實例化instance,切換到了線程2運行,線程2判斷null == instance也爲true。就會實例化多次
*/
public class Singleton2{
    
    private static Singleton2 instance = null;

    //私有化構造函數,防止被外部實例化
    private Singleton2(){}

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

}

3.懶漢式 + 同步方法(synchronized)

synchronized 控制了整個方法,容易多線程性能低下。

採用懶漢式 + 數據同步方式既滿足了懶加載又能百分之百保證instance實例的唯一性,但是synchronized 關鍵字天生的排他性導致了getInstance方法只能在同一時刻被一個線程所訪問,性能低下


public class Singleton3{
    
    private static Singleton3 instance = null;

    //私有化構造函數,防止被外部實例化
    private Singleton3(){}

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

}

4.Double-check 

double-check 有可能會引起空指針的問題。

關鍵點在於:根據JVM指令重排序和Happens-Before規則,這兩者之間的實例化順序並無前後關係的約束 

那麼極有可能instance最先被實例化,而conn並未完成實例化,未完成初始化的實例調用其他方法將會拋出空指針異常。

public class Singleton4{

    private static Singleton4 instance = null;

    private String conn;


    //私有化構造函數,防止被外部實例化
    private Singleton4(){
        this.conn = "test";
    }

    public static Singleton4 getInstance(){
        if(instance = null){
            synchronized(Singleton4.class){
                if(instance == null){
                    instance = new Singleton4();
                }
            }
        }
        return instance;
    }
}

5.Volatile + double + check

java有用戶內存和主內存的區別,對於變量以volatile 聲明以保證變量在內存的可見性,即可消除這個空指針隱患

public class Singleton5{

    private static Singleton5 instance = null;

    private String conn;


    //私有化構造函數,防止被外部實例化
    private Singleton5(){
        this.conn = "test";
    }

    public static Singleton5 getInstance(){
        if(instance = null){
            synchronized(Singleton5.class){
                if(instance == null){
                    instance = new Singleton5();
                }
            }
        }
        return instance;
    }
}

6.Holer方式

即以靜態內部類的方式提供示實例

該方法又是同步方法,保證了內存的可見性,JVM的順序性和原子性。Holder方式是單例設計最好的設計之一

public class Singleton6{
    
    //靜態內部類提供實例
    private static class Holder{
        private static Singleton6 instance = new Singleton6();
    } 

    public static Singleton6 getInstance(){
        return Holder.instance;
    }
}

7.枚舉方法,線程安全,不能懶加載

枚舉類型不允許被繼承,同樣是線程安全且只能被實例化一次,但是枚舉不能夠懶加載,對於Singleton6主動使用,比如調用其中靜態方法則INSTANCE會立即得到實例化

public enum Singleton7{
    INSTANCE;

    Singleton7(){}

    public static void method(){
        //調用該方法,則會主動使用Singleton7, INSTANCE則會被實例化
    }

    public static Singleton7 getInstance(){
        return INSTANCE;
    }
}

可改造類似用Holder的方式支持懶加載

public class Singleton7_2{
    
    private Singleton7_2(){}

    private enum Holder{
        INSTANCE;
        private Singleton7_2 instance;
        
        Holder(){
            this.instance = new Singleton7_2();
        }

        public Singleton7_2 getInstance(){
            return instance;
        }
    }

    public static Singleton7_2 getInstance(){
        return Holder.INSTANCE.getINstance();
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章