少年阿賓

          那些青春的歲月

            BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
            500 Posts :: 0 Stories :: 135 Comments :: 0 Trackbacks
          枚舉單例模式:
          關于單例模式的實現有很多種,網上也分析了如今實現單利模式最好用枚舉,好處不外乎三點:
          1.線程安全 2.不會因為序列化而產生新實例 3.防止反射攻擊
          1.線程安全 
          下面這段代碼就是聲明枚舉實例的通常做法,它可能還包含實例變量和實例方法,但是為了簡單起見,我并沒有使用這些東西,僅僅需要小心的是如果你正在使用實例方法,那么你需要確保線程安全(如果它影響到其他對象的狀態的話)。默認枚舉實例的創建是線程安全的,但是在枚舉中的其他任何方法由程序員自己負責。
          關于線程安全的保證,其實是通過類加載機制來保證的,我們看看INSTANCE的實例化時機,是在static塊中,JVM加載類的過程顯然是線程安全的。
          static {};
            Code:
             0:   new     #12; //class com/abin/lee/spring/util/Singleton$1
             3:   dup
             4:   ldc     #14; //String INSTANCE
             6:   iconst_0
             7:   invokespecial   #15; //Method com/abin/lee/spring/util/Singleton$1."<init>":(Ljava/lang/String;I)V
             10:  putstatic       #19; //Field INSTANCE:Lcom/abin/lee/spring/util/Singleton;
             13:  iconst_1
             14:  anewarray       #1; //class com/abin/lee/spring/util/Singleton
             17:  dup
             18:  iconst_0
             19:  getstatic       #19; //Field INSTANCE:Lcom/abin/lee/spring/util/Singleton;
             22:  aastore
             23:  putstatic       #21; //Field ENUM$VALUES:[Lcom/abin/lee/spring/util/Singleton;
             26:  return
          線程安全,從反編譯后的類源碼中可以看出也是通過類加載機制保證的,應該是這樣吧

          2.不會因為序列化而產生新實例
          枚舉自己處理序列化
          傳統單例存在的另外一個問題是一旦你實現了序列化接口,那么它們不再保持單例了,因為readObject()方法一直返回一個新的對象就像java的構造方法一樣,你可以通過使用readResolve()方法來避免此事發生,看下面的例子:
          //readResolve to prevent another instance of Singleton
              private Object readResolve(){
                  return INSTANCE;
              }
          這樣甚至還可以更復雜,如果你的單例類維持了其他對象的狀態的話,因此你需要使他們成為transient的對象。但是枚舉單例,JVM對序列化有保證。
          優點:不僅能避免多線程同步問題,而且還能防止反序列化重新創建新的對象


          3.防止反射攻擊
          反射攻擊,我有自己試著反射攻擊了以下,不過報錯了...看了下方的反編譯類源碼,明白了,因為單例類的修飾是abstract的,所以沒法實例化。(解決













          靜態內部類:
          // Correct lazy initialization in Java 
          @ThreadSafe
          class Foo {
              private static class HelperHolder {
                 public static Helper helper = new Helper();
              }
           
              public static Helper getHelper() {
                  return HelperHolder.helper;
              }
          }

          它利用了內部靜態類只有在被引用的時候才會被加載的規律。

          這樣一來,一旦內部的HelperHolder被引用了,它就會首先被JVM加載,進行該類的靜態域的初始化,從而使得Helper這一單例類被初始化。它之所以是線程安全的,也是托了JVM的福,因為JVM對于類的加載這一過程是線程安全的。

          posted on 2015-03-17 15:15 abin 閱讀(366) 評論(0)  編輯  收藏 所屬分類: PatternDesigns
          主站蜘蛛池模板: 酉阳| 天镇县| 赣州市| 治县。| 卓尼县| 富裕县| 康平县| 洞头县| 卢龙县| 江永县| 金川县| 迁西县| 泽库县| 长葛市| 富顺县| 石门县| 毕节市| 南投县| 西乌| 长武县| 腾冲县| 贵港市| 龙海市| 建平县| 漳平市| 乃东县| 遂溪县| 大石桥市| 白玉县| 行唐县| 神木县| 永春县| 凤山县| 商洛市| 佳木斯市| 乌什县| 宜兰县| 兴山县| 黎平县| 介休市| 新密市|