天天看點

Singleton 單例模式很多種寫法

      以前我就知道單例模式的兩種寫法,如今經發現那兩種是很基礎的用法,下面分享一下,各種單例的寫法吧,我個人還是比較喜歡用枚舉類的方式寫單例,優雅簡潔,還安全。

Singleton 單例模式

第一種型式,餓漢式,在環境初始化,即JVM開始運作時就生成執行個體。

public class Singleton {

        private static Singleton instance = new Singleton();

        private Singleton(){}

        public static Singleton getInstance() {

                return Singleton.instance;

       }

}

第二種型式,懶漢式,即需要使用時才生成執行個體,可以減少記憶體使用。

public class Singleton {

        private static Singleton instance = null;

        private Singleton(){}

        public static Singleton getInstance() {

                synchronized (Singleton.class) {

                        if(null == instance) {

                                instance = new Singleton();

                       }

                }

                return instance;

        }

}

這種用了synchronized 傳說也會出現邏輯不嚴密而new出兩個執行個體的情況,是以又出現了一種變式,即雙重鎖機制,然而這種在苛刻的條件下依舊邏輯不夠嚴密。

public class Singleton {

        private static Singleton instance = null;

        private Singleton(){}

        public static Singleton getInstance() {

                if(null == instance) {

                        synchronized (Singleton.class) {

                                if(null == instance) {

                                        instance = new Singleton();

                                }

                        }

                }

                return instance;

        }

}

第三種形式,枚舉形式,也是我現在比較常用的形式。

public enum Singleton {

        INSTANCE;

        public static Singleton getInstance() {

                //do your Logic

                  // return INSTANCE;

        }

}

這種方式除了更簡明,還等同于public屬性方式。免費提供了序列化機制,即使面對尖端的序列化或者反射攻擊,它都提供了堅實的單例。

 第四種形式,延遲加載,解決鎖的同步問題,并且安全可靠。

public class SingletonFactory {

        private static class SingletonHolder {

                public static Singleton INSTANCE = new Singleton();

        }

        public static Singleton getInstance() {

                return SingletonHolder.INSTANCE;

        }

}

這種方式也是惰性初始化,在真正使用Holder時才初始化,而且因為是靜态初始階段進行的,是以不再需要額外同步。

用這種方法解決延遲加載最合适不過了。

建議使用後兩種方式的單例形式,代碼看起來也很優雅 (以上示例private 的構造方法别忘記哦)。

這裡有一篇文章的測試代碼可以說明用第三種方式的堅實性和防止攻擊造成單例失效 http://lzh166.javaeye.com/blog/620817

另外,還有用反射等比較鑽牛角尖的方法建構單例的形式,以及一些測試,可以看一下這篇分析的文章 http://www.javaeye.com/topic/60179