国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Java > 正文

Java實現單例模式之餓漢式、懶漢式、枚舉式

2019-11-26 13:39:49
字體:
來源:轉載
供稿:網友

單例模式的實現(5種)

常用:

餓漢式(線程安全,調用效率高,但是不能延時加載)
懶漢式(線程安全,調用效率不高,可以延時加載)

其他:

雙重檢測鎖式(由于jvm底層內部模型原因,偶爾會出問題,不建立使用)
靜態內部類式(線程安全,調用效率高,但是可以延時加載)
枚舉單例(線程安全,調用效率高,不能延時加載)
餓漢式單例具體代碼如下:

package com.lcx.mode;   /**  *  * 餓漢式單例,不管以后用不用這個對象,我們一開始就創建這個對象的實例,  * 需要的時候就返回已創建好的實例對象,所以比較饑餓,故此叫餓漢式單例。  * @author qq1013985957  *  */ public class SingletonHanger {   private static final SingletonHanger instance = new SingletonHanger();   private SingletonHanger() {   }   public static SingletonHanger getInstance(){     return instance;   } } /**  * 懶漢漢式單例,在需要單例對象的時候,才創建唯一的單例對象,以后再次調用,返回的也是第一創建的單例對象  * 將靜態成員初始化為null,在獲取單例的時候才創建,故此叫懶漢式。  * @author qq1013985957  *  */ class SingletonLazy{   private static SingletonLazy instance = null;   private SingletonLazy() {   }   /**    * 此方法實現的單例,無法在多線程中使用,多線可以同時進入if方法,會導致生成多個單例對象。    * @return    */   public static SingletonLazy getInstance1(){     if(instance==null){       instance = new SingletonLazy();     }     return instance;   }   /**    * 大家都會想到同步,可以同步方法實現多線程的單例    * 但是這種方法不可取,嚴重影響性能,因為每次去取單例都要檢查方法,所以只能用同步代碼塊的方式實現同步。    * @return    */   public static synchronized SingletonLazy getInstance2(){     if(instance==null){       instance = new SingletonLazy();     }     return instance;   }   /**    * 用同步代碼塊的方式,在判斷單例是否存在的if方法里使用同步代碼塊,在同步代碼塊中再次檢查是否單例已經生成,    * 這也就是網上說的 雙重檢查加鎖的方法    * @return    */   public static synchronized SingletonLazy getInstance3(){     if(instance==null){       synchronized (SingletonLazy.class) {         if(instance==null){           instance = new SingletonLazy();         }       }     }     return instance;   } } /**  *  * 使用枚舉實現單例模式,也是Effective Java中推薦使用的方式  * 根據具體情況進行實例化,對枚舉不熟悉的同學,可以參考我的博客 JAVA 枚舉類的初步理解。  * 它的好處:更加簡潔,無償提供了序列化機制,絕對防止多次實例化,即使面對復雜的序列和反射攻擊。  * @author qq1013985957  *  */ enum SingletionEnum{   SingletionEnum("單例的枚舉方式");   private String str ;   private SingletionEnum(String str){     this.setStr(str);   }   public String getStr() {     return str;   }   public void setStr(String str) {     this.str = str;   }    } 

以上的單例模式就不測試,大家可以去測試,判斷對象的hashcode是否一致來判斷是否為同一個對象。

惡漢式、懶漢式的方式還不能防止反射來實現多個實例,通過反射的方式,設置ACcessible.setAccessible方法可以調用私有的構造器,可以修改構造器,讓它在被要求創建第二個實例的時候拋出異常。

其實這樣還不能保證單例,當序列化后,反序列化是還可以創建一個新的實例,在單例類中添加readResolve()方法進行防止。
懶漢漢式單例代碼如下:

package com.lcx.mode;  import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException;  /**  * 懶漢漢式單例,在需要單例對象的時候,才創建唯一的單例對象,以后再次調用,返回的也是第一創建的單例對象  * 將靜態成員初始化為null,在獲取單例的時候才創建,故此叫懶漢式。  * @author qq1013985957  *  */ public class Singleton implements Serializable{   /**    *    */   private static final long serialVersionUID = -5271537207137321645L;   private static Singleton instance = null;   private static int i = 1;   private Singleton() {     /**      * 防止反射攻擊,只運行調用一次構造器,第二次拋異常      */     if(i==1){       i++;     }else{       throw new RuntimeException("只能調用一次構造函數");     }     System.out.println("調用Singleton的私有構造器");        }   /**    * 用同步代碼塊的方式,在判斷單例是否存在的if方法里使用同步代碼塊,在同步代碼塊中再次檢查是否單例已經生成,    * 這也就是網上說的 雙重檢查加鎖的方法    * @return    */   public static synchronized Singleton getInstance(){     if(instance==null){       synchronized (Singleton.class) {         if(instance==null){           instance = new Singleton();         }       }     }     return instance;   }   /**    *    * 防止反序列生成新的單例對象,這是effective Java 一書中說的用此方法可以防止,具體細節我也不明白    * @return    */   private Object readResolve(){     return instance;   }   public static void main(String[] args) throws Exception {     test1();     test2();   }   /**    * 測試 反序列 仍然為單例模式    * @throws Exception    */   public static void test2() throws Exception{     Singleton s = Singleton.getInstance();     ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(new File("E://Singleton.txt")));     objectOutputStream.writeObject(s);     ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(new File("E://Singleton.txt")));     Object readObject = objectInputStream.readObject();     Singleton s1 = (Singleton)readObject;     System.out.println("s.hashCode():"+s.hashCode()+",s1.hashCode():"+s1.hashCode());          objectOutputStream.flush();     objectOutputStream.close();     objectInputStream.close();   }   /**    * 測試反射攻擊    * @throws Exception    */   public static void test1(){     Singleton s = Singleton.getInstance();     Class c = Singleton.class;     Constructor privateConstructor;     try {       privateConstructor = c.getDeclaredConstructor();       privateConstructor.setAccessible(true);       privateConstructor.newInstance();     } catch (Exception e) {       e.printStackTrace();     }   } } 

驗證反射攻擊結果:

如果不添加readResolve方法的結果:

添加readResolve方法的結果:

感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 阜阳市| 松原市| 衡阳县| 和平县| 舞钢市| 阿图什市| 轮台县| 南召县| 东乌| 望奎县| 闸北区| 尚志市| 石城县| 马鞍山市| 长汀县| 扎兰屯市| 科技| 乐至县| 河南省| 邢台市| 柳江县| 乡宁县| 弥渡县| 齐河县| 离岛区| 静安区| 灌云县| 长沙县| 新龙县| 青川县| 略阳县| 拜城县| 苗栗市| 孟村| 洪雅县| 南通市| 永仁县| 邯郸县| 株洲县| 海丰县| 曲松县|