幾種單例模式的實現

1.餓漢式html

public class Singleton        
{        
    private static Singleton instance = new Singleton();        
    private Singleton(){        
        …        
    }        
    public static Singleton getInstance(){        
             return instance;         
    }        
}

缺點:第一次加載類的時候會連帶着建立Singleton實例,這樣的結果與咱們所指望的不一樣,由於建立實例的時候可能並非咱們須要這個實例的時候。同時若是這個Singleton實例的建立很是消耗系統資源,而應用始終都沒有使用Singleton實例,那麼建立Singleton消耗的系統資源就被白白浪費了。安全

 

2.懶漢式多線程

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

缺點:存在多線程併發問題,併發下可能建立多個對象。併發

3.解決併發問題函數

方法上使用Class鎖機制線程

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

缺點:加載方法上鎖粒度太大,影響併發。實際上當單例實例被建立之後,其後的請求沒有必要再使用互斥機制了。htm

用double-checked locking將鎖縮減至代碼塊級別對象

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

 對於JVM而言,它執行的是一個個Java指令。在Java指令中建立對象和賦值操做是分開進行的,也就是說instance = new Singleton();語句是分兩步執行的。可是JVM並不保證這兩個操做的前後順序,也就是說有可能JVM會爲新的Singleton實例分配空間,而後直接賦值給instance成員,而後再去初始化這個Singleton實例。這樣就使出錯成爲了可能。blog

使用volatile防止重排序:排序

public class Singleton{        
    private static volatile Singleton instance = null;        
    private Singleton(){ … }        
    public static Singleton getInstance(){
        if (instance == null) 
            synchronized(instance){ 
                if(instance == null) 
                    instance = new Singleton();
    }
    return instance;      
}

 

不加鎖:爲了實現慢加載,而且不但願每次調用getInstance時都必須互斥執行。

public class Singleton{        
    private Singleton(){        
        …        
    }        
    private static class SingletonContainer{        
        private static Singleton instance = new Singleton();        
    }        
    public static Singleton getInstance(){        
        return SingletonContainer.instance;        
    }        
}

JVM內部的機制可以保證當一個類被加載的時候,這個類的加載過程是線程互斥的。這樣當咱們第一次調用getInstance的時候,JVM可以幫咱們保證instance只被建立一次,而且會保證把賦值給instance的內存初始化完畢,這樣咱們就不用擔憂3.2中的問題。此外該方法也只會在第一次調用的時候使用互斥機制,這樣就解決了3.1中的低效問題。最後instance是在第一次加載SingletonContainer類時被建立的,而SingletonContainer類則在調用getInstance方法的時候纔會被加載,所以也實現了惰性加載。

 

https://www.cnblogs.com/jingpeipei/p/5771716.html

 

/** 推薦
 * 靜態內部類實現單例模式(懶加載的一種)
 * 靜態內部類只有在調用的時候才初始化,而且初始化過程線程安全。
 * instance不提供修改實例方法,靜態變量只初始化一次,因此final修飾不加也同樣。
 * 兼備了併發高效調用和懶加載的優點。
 * 結論:線程安全,調用效率高,而且能夠延時加載。
 */
public class StaticClassSingleton {
    //私有構造函數
    private StaticClassSingleton(){};

    //靜態內部類
    private static class SingletonClassInstance{
        private static final StaticClassSingleton INSTANCE =
                new StaticClassSingleton();
    }

    //提供實例的調用方法
    public static StaticClassSingleton getInstance(){
        return SingletonClassInstance.INSTANCE;
    }
}

/** 推薦
 * 枚舉類對象自己就是一個單例對象。
 * 沒有延時加載的特性。
 * 能夠自然的防止反射和反序列化的漏洞,由於枚舉是基於JVM底層實現的。
 * 結論:線程安全,調用效率高,可是不是延時加載,自然防止反射和反序列化漏洞。
 */
public enum  EnumSingleton {
    /**
     * 枚舉對象
     */
    INSTANCE;

    /**      * 成員方法      */     public void singletonOperation(){         //單例對象的其它操做實現。     } }  

相關文章
相關標籤/搜索