問(wèn)題來(lái)源

  什么是單例?它的運(yùn)用場(chǎng)景是什么?

  單例模式是指保證在系統(tǒng)中只存在某類唯一對(duì)象。運(yùn)用場(chǎng)景隨處可見,例如工具類、Spring容器默認(rèn)new對(duì)象等。

  單例模式有幾種實(shí)現(xiàn)方式?

  餓漢式、懶漢式、雙重檢查鎖式、內(nèi)部類式、枚舉式。

  推薦使用方式?

  餓漢式、內(nèi)部類式。

餓漢式

  餓漢式顧名思義餓,那么當(dāng)應(yīng)用程序一開始類加載,類的對(duì)象立馬實(shí)例化加載至JVM。

大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計(jì)算培訓(xùn),高端軟件開發(fā)培訓(xùn),項(xiàng)目經(jīng)理培訓(xùn)

 1 public class SingletonClass { 2     /** 3      * 優(yōu)點(diǎn):調(diào)用效率高。 4      * 缺點(diǎn):沒有延遲加載。 5      */ 6     private static SingletonClass instance =new SingletonClass(); 7      8     public static SingletonClass getInstance(){ 9         return instance;10     }11 }

大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計(jì)算培訓(xùn),高端軟件開發(fā)培訓(xùn),項(xiàng)目經(jīng)理培訓(xùn)

   為什么調(diào)用效率高?沒有延遲加載?

  答:假設(shè)在高并發(fā)的場(chǎng)景下,有10W+并發(fā)調(diào)用,不需要同步處理??梢灾苯釉诙褍?nèi)存直接獲取對(duì)象不需要任何等待。

    同樣,它沒有延遲加載,如果它是需要消耗很大內(nèi)存的對(duì)象,最開始就加載入堆內(nèi)存,而用戶暫時(shí)不需要。這樣就會(huì)嚴(yán)重占用堆內(nèi)存,影響運(yùn)行效率。

 懶漢式

  導(dǎo)引:腦洞大開的程序員們說(shuō):上述問(wèn)題還不簡(jiǎn)單,當(dāng)調(diào)用的時(shí)候在new對(duì)象不就行。于是出現(xiàn)了懶漢式的雛形版本。

大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計(jì)算培訓(xùn),高端軟件開發(fā)培訓(xùn),項(xiàng)目經(jīng)理培訓(xùn)

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

大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計(jì)算培訓(xùn),高端軟件開發(fā)培訓(xùn),項(xiàng)目經(jīng)理培訓(xùn)

   懶漢式顧名思義懶,就是延遲加載,當(dāng)被調(diào)用的時(shí)候再實(shí)例化。

  問(wèn)題:如果你是初出茅廬的應(yīng)屆生寫成這樣,估計(jì)面試官也不會(huì)追究什么。如果你是有一年工作年限的程序員,估計(jì)面試官就會(huì)聲討你了。假設(shè),并發(fā)數(shù)10W+,它就將被蹂躪的不堪入目。那么我們需要怎么解決呢?加上同步操作就大功告成。

大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計(jì)算培訓(xùn),高端軟件開發(fā)培訓(xùn),項(xiàng)目經(jīng)理培訓(xùn)

 1 public class SingletonClass { 2      3     //調(diào)用效率低、延遲加載 4     private static SingletonClass instance; 5      6     public static synchronized SingletonClass getInstance(){ 7         if(null==instance){ 8             instance=new SingletonClass(); 9         }10         return instance;11     }12 }

大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計(jì)算培訓(xùn),高端軟件開發(fā)培訓(xùn),項(xiàng)目經(jīng)理培訓(xùn)

   問(wèn)題:從效率維度考慮,估計(jì)這樣已經(jīng)完美了吧?但是,從安全緯度考慮,依然隱隱約約存在問(wèn)題。如果是接觸過(guò)反射、反序列化的同學(xué),我們一起來(lái)繼續(xù)探討。

大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計(jì)算培訓(xùn),高端軟件開發(fā)培訓(xùn),項(xiàng)目經(jīng)理培訓(xùn)

/**
 * 通過(guò)反射破壞懶漢式單例
 * @author aaron */public class Client {    public static void main(String[] args) throws Exception {
        SingletonClass clazzOne=SingletonClass.getInstance();
        SingletonClass clazzTwo=SingletonClass.getInstance();
        
        System.out.println("clazzOne-hasCode:"+clazzOne.hashCode());
        System.out.println("clazzTwo-hasCode:"+clazzTwo.hashCode());
        
        Class<SingletonClass> clazz=(Class<SingletonClass>)Class.forName("singleton.SingletonClass");
        Constructor<SingletonClass> c=clazz.getConstructor(null);
        c.setAccessible(true);
        SingletonClass clazzThree=c.newInstance();
        SingletonClass clazzFour=c.newInstance();
        System.out.println("clazzThree-hasCode:"+clazzThree.hashCode());
        System.out.println("clazzFour-hasCode:"+clazzFour.hashCode());
    }
}

大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計(jì)算培訓(xùn),高端軟件開發(fā)培訓(xùn),項(xiàng)目經(jīng)理培訓(xùn)

 大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計(jì)算培訓(xùn),高端軟件開發(fā)培訓(xùn),項(xiàng)目經(jīng)理培訓(xùn)

大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計(jì)算培訓(xùn),高端軟件開發(fā)培訓(xùn),項(xiàng)目經(jīng)理培訓(xùn)

 1 public class SingletonClass implements Serializable{ 2      3     private static SingletonClass instance; 4      5     public static synchronized SingletonClass getInstance(){ 6         if(null==instance){ 7             instance=new SingletonClass(); 8         } 9         return instance;10     }11     12     public static void main(String[] args) throws Exception {13         SingletonClass clazzOne=SingletonClass.getInstance();14         SingletonClass clazzTwo=SingletonClass.getInstance();    
15         System.out.println("clazzOne-hasCode:"+clazzOne.hashCode());16         System.out.println("clazzTwo-hasCode:"+clazzTwo.hashCode());17         18     19         FileOutputStream fos=new FileOutputStream(new File("f:/test.txt"));20         ObjectOutputStream bos=new ObjectOutputStream(fos);21         bos.writeObject(clazzOne);22         bos.close();23         fos.close();24         25         FileInputStream fis=new FileInputStream(new File("f:/test.txt"));26         ObjectInputStream bis=new ObjectInputStream(fis);27         SingletonClass clazzThree=(SingletonClass) bis.readObject();28         System.out.println("clazzThree-hasCode:"+clazzThree.hashCode());29     }30 }

大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計(jì)算培訓(xùn),高端軟件開發(fā)培訓(xùn),項(xiàng)目經(jīng)理培訓(xùn)

 大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計(jì)算培訓(xùn),高端軟件開發(fā)培訓(xùn),項(xiàng)目經(jīng)理培訓(xùn)

  問(wèn)題:這么輕易就被破解了?那怎么解決呢?

大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計(jì)算培訓(xùn),高端軟件開發(fā)培訓(xùn),項(xiàng)目經(jīng)理培訓(xùn)

public class SingletonClass implements Serializable{    
    private static SingletonClass instance;    
    private SingletonClass(){        //防止被反射
        if(null!=instance){            throw new RuntimeException();
        }
    }    
    public static synchronized SingletonClass getInstance(){        if(null==instance){
            instance=new SingletonClass();
        }        return instance;
    }    
    //當(dāng)沒有定義這方法時(shí),反序列化默認(rèn)是重新new對(duì)象。    //反序列化時(shí),如果定義了readResolve()則直接返回此方法指定的對(duì)象。而不需要單獨(dú)再創(chuàng)建新對(duì)象!
    private Object readResolve() throws ObjectStreamException{        return instance;
    }
}

大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計(jì)算培訓(xùn),高端軟件開發(fā)培訓(xùn),項(xiàng)目經(jīng)理培訓(xùn)

 雙重檢查鎖與內(nèi)部類

  雙重檢查鎖與內(nèi)部類的方式:緣由懶漢式、餓漢式要么存在調(diào)用效率低或者運(yùn)行效率低問(wèn)題。而這兩種方式取前兩者的優(yōu)點(diǎn)為自己所用。

大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計(jì)算培訓(xùn),高端軟件開發(fā)培訓(xùn),項(xiàng)目經(jīng)理培訓(xùn)

 1 /** 2  * 單例模式-雙重檢查鎖 3  * @author aaron 4  */ 5 public class SingletonClass{ 6     private static SingletonClass instance; 7      8     public static  SingletonClass getInstance(){ 9         if(null==instance){10             synchronized (SingletonClass.class) {11                 if(instance==null){12                     instance=new SingletonClass();13                 }14             }15         }16         return instance;17     }18 }

大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計(jì)算培訓(xùn),高端軟件開發(fā)培訓(xùn),項(xiàng)目經(jīng)理培訓(xùn)

   問(wèn)題:緣由JVM對(duì)于此種方式的同步控制,并不穩(wěn)定,當(dāng)高并發(fā)的時(shí)候,可能會(huì)出現(xiàn)問(wèn)題,并不推薦使用這種方式。理論上來(lái)說(shuō),它是不存在問(wèn)題的。

大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計(jì)算培訓(xùn),高端軟件開發(fā)培訓(xùn),項(xiàng)目經(jīng)理培訓(xùn)

 1 /** 2  * 單例模式-內(nèi)部類的方式 3  * @author aaron 4  */ 5 public class SingletonClass{ 6      7     private static class InnerClass{ 8         public static SingletonClass instance=new SingletonClass(); 
 9     }10     11     public static SingletonClass getInstance(){12         return InnerClass.instance;13     }14 }

大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計(jì)算培訓(xùn),高端軟件開發(fā)培訓(xùn),項(xiàng)目經(jīng)理培訓(xùn)

大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計(jì)算培訓(xùn),高端軟件開發(fā)培訓(xùn),項(xiàng)目經(jīng)理培訓(xùn)

1 /**2  * 單例模式-枚舉的方式3  * @author aaron4  */5 public enum SingletonClass{6     INSTANCE7 }

大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計(jì)算培訓(xùn),高端軟件開發(fā)培訓(xùn),項(xiàng)目經(jīng)理培訓(xùn)

版權(quán)聲明

  作者:xiaoyongAaron(邱勇)

  出處:http://www.cnblogs.com/qiuyong/

  您的支持是對(duì)博主深入思考總結(jié)的最大鼓勵(lì)。

  本文版權(quán)歸作者所有,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,且在文章頁(yè)面明顯位置給出原文連接,尊重作者的勞動(dòng)成果。

一直特立獨(dú)行的二本僧,書寫屬于他的天空

http://www.cnblogs.com/qiuyong/p/6917801.html