Java中的單例模式


 一、餓漢式

public class HungerySingleton {
 
 
    //ClassLoader 類加載時立即實例化對象,僅實例化一次,線程安全的
    private static HungerySingleton hungerySingleton = new HungerySingleton();
 
 
    public static HungerySingleton getInstance(){
        return hungerySingleton;
    }
 
    //利用線程輸出(后面就不寫了哈)
    public static void main(String[]args){
        for(int i=0;i<20;i++){
            Thread thread =new Thread() {
                @Override
                public void run() {
                    HungerySingleton hungerySingleton = HungerySingleton.getInstance();
                    System.out.println(hungerySingleton);
                }
            };
            thread.start();
        }
    }
}

優點:僅實例化一次,線程是安全的。獲取實例的速度快

缺點:類加載時立即實例化對象,可能實例化的對象不被使用,造成內存的浪費。
 
 

二、懶漢式

public class HoonSingleton {
    //不能保證實例對象的唯一性
    private static HoonSingleton hoonSingleton = null;
 
 
    public static HoonSingleton getInstance(){
        if(hoonSingleton==null){
            hoonSingleton = new HoonSingleton();
        }
        return hoonSingleton;
    }
}

優點:獲取實例時才進行實例的初始化,節省系統資源

缺點:1、如果獲取實例時,初始化的工作量較多,加載速度會變慢,影響系統系能
          2、每次獲取實例都要進行非空檢查,系統開銷大
          3、非線程安全。注意紅色代碼標記,當多個線程同時getInstance()時,可能hoonSingleton實例化未完成,hoonSingleton==null判斷均為true,造成對象重復實例化。
 
 

三、雙重檢查鎖 DCL(double-checked locking)+ volatile

public class HoonSingleton {
 
    private static volatile HoonSingleton hoonSingleton = null;
 
    // 使用sync同步HoonSingleton.class 兩次判斷hoonSingleton是否為null 避免並發導致hoonSingleton被重新實例化
    // 並沒有對整個方法使用sync,鎖的粒度變小了,實現了實例對象的唯一性
    public static HoonSingleton getInstance(){
        if(hoonSingleton==null){
            synchronized (HoonSingleton.class) {
                if(hoonSingleton==null) {
                    hoonSingleton = new DCL();
                }
            }
        }
        return hoonSingleton;
    }

優點:1、線程安全。注意加粗標記,進行雙重檢查,保證只在實例未初始化前進行同步,效率高。

          2、對hoonSingleton使用volatile修飾符,避免實例化過程中產生的重排序。避免NPE拋出。
缺點:實例非空判斷,耗費一定資源
 
 

四、Holder方式 廣泛使用的一種單例模式

//聲明類的時候、成員變量中不聲明實例變量,而是放到內部靜態類中
public class HolderDemo {
 
    private static class Holder{
        private static HolderDemo instance = new HolderDemo();
    }
 
    public static HolderDemo getInstance(){
        return Holder.instance;
    }
}

優點:1、內部類只有在外部類被調用才加載,從而實現了延遲加載

          2、線程安全。且不用加鎖。
 
 
 

五、使用枚舉的單例模式,本質上和餓漢模式沒有任何區別,只是采用Enum實現的更巧妙了

public enum EnumSingleton {
    //枚舉類型,在加載的時候實例化。
    INSTANCE;
    public static EnumSingleton getInstance(){
        return INSTANCE;
    }
}

優點:僅實例化一次,線程是安全的。獲取實例的速度快

缺點:類加載時立即實例化對象,可能實例化的對象不被使用,造成內存的浪費。
 
 

六、枚舉和懶漢模式相結合

public class EnumSingletonDemo {
 
    private enum EnumHolder{
        INSTANCE;
        private static  EnumSingletonDemo instance=null;
  
        private EnumSingletonDemo getInstance(){
            if(instance ==null) {
                instance = new EnumSingletonDemo();
            }
            return instance;
        }
    }
  
    //實現懶加載
    public static EnumSingletonDemo  getInstance(){
        return EnumHolder.INSTANCE.getInstance();
    }

優點:1、線程安全。且不用加鎖。

          2、實現了懶加載
缺點:仍然需要實例非空判斷,耗費一定資源
 
 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM