<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆-199  評(píng)論-203  文章-11  trackbacks-0
      單實(shí)例Singleton設(shè)計(jì)模式可能是被討論和使用的最廣泛的一個(gè)設(shè)計(jì)模式了,這可能也是面試中問(wèn)得最多的一個(gè)設(shè)計(jì)模式了。這個(gè)設(shè)計(jì)模式主要目的是想在整個(gè)系統(tǒng)中只能出現(xiàn)一個(gè)類的實(shí)例。這樣做當(dāng)然是有必然的,比如你的軟件的全局配置信息,或者是一個(gè)Factory,或是一個(gè)主控類,等等。你希望這個(gè)類在整個(gè)系統(tǒng)中只能出現(xiàn)一個(gè)實(shí)例。當(dāng)然,作為一個(gè)技術(shù)負(fù)責(zé)人的你,你當(dāng)然有權(quán)利通過(guò)使用非技術(shù)的手段來(lái)達(dá)到你的目的。比如:你在團(tuán)隊(duì)內(nèi)部明文規(guī)定,“XX類只能有一個(gè)全局實(shí)例,如果某人使用兩次以上,那么該人將被處于2000元的罰款!”(呵呵),你當(dāng)然有權(quán)這么做。但是如果你的設(shè)計(jì)的是東西是一個(gè)類庫(kù),或是一個(gè)需要提供給用戶使用的API,恐怕你的這項(xiàng)規(guī)定將會(huì)失效。因?yàn)椋銦o(wú)權(quán)要求別人會(huì)那么做。所以,這就是為什么,我們希望通過(guò)使用技術(shù)的手段來(lái)達(dá)成這樣一個(gè)目的的原因。

        本文會(huì)帶著你深入整個(gè)Singleton的世界,當(dāng)然,我會(huì)放棄使用C++語(yǔ)言而改用Java語(yǔ)言,因?yàn)槭褂肑ava這個(gè)語(yǔ)言可能更容易讓我說(shuō)明一些事情。

        Singleton的教學(xué)版本

        這里,我將直接給出一個(gè)Singleton的簡(jiǎn)單實(shí)現(xiàn),因?yàn)槲蚁嘈拍阋呀?jīng)有這方面的一些基礎(chǔ)了。我們姑且把這具版本叫做1.0版

     // version 1.0
    public class Singleton
    {
    private static final Singleton singleton = null;

    private Singleton()
    {
    }
    public static Singleton getInstance()
    {
    if (singleton== null)
    {
    singleton= new Singleton();
    }
    return singleton;
    }
    }

        在上面的實(shí)例中,我想說(shuō)明下面幾個(gè)Singleton的特點(diǎn):(下面這些東西可能是盡人皆知的,沒(méi)有什么新鮮的)

        私有(private)的構(gòu)造函數(shù),表明這個(gè)類是不可能形成實(shí)例了。這主要是怕這個(gè)類會(huì)有多個(gè)實(shí)例。

        即然這個(gè)類是不可能形成實(shí)例,那么,我們需要一個(gè)靜態(tài)的方式讓其形成實(shí)例:getInstance()。注意這個(gè)方法是在new自己,因?yàn)槠淇梢栽L問(wèn)私有的構(gòu)造函數(shù),所以他是可以保證實(shí)例被創(chuàng)建出來(lái)的。

        在getInstance()中,先做判斷是否已形成實(shí)例,如果已形成則直接返回,否則創(chuàng)建實(shí)例。

        所形成的實(shí)例保存在自己類中的私有成員中。

        我們?nèi)?shí)例時(shí),只需要使用Singleton.getInstance()就行了。

        當(dāng)然,如果你覺(jué)得知道了上面這些事情后就學(xué)成了,那我給你當(dāng)頭棒喝一下了,事情遠(yuǎn)遠(yuǎn)沒(méi)有那么簡(jiǎn)單。

        Singleton的實(shí)際版本

        上面的這個(gè)程序存在比較嚴(yán)重的問(wèn)題,因?yàn)槭侨中缘膶?shí)例,所以,在多線程情況下,所有的全局共享的東西都會(huì)變得非常的危險(xiǎn),這個(gè)也一樣,在多線程情況下,如果多個(gè)線程同時(shí)調(diào)用getInstance()的話,那么,可能會(huì)有多個(gè)進(jìn)程同時(shí)通過(guò) (singleton== null)的條件檢查,于是,多個(gè)實(shí)例就創(chuàng)建出來(lái),并且很可能造成內(nèi)存泄露問(wèn)題。嗯,熟悉多線程的你一定會(huì)說(shuō)——“我們需要線程互斥或同步”,沒(méi)錯(cuò),我們需要這個(gè)事情,于是我們的Singleton升級(jí)成1.1版,如下所示:

     // version 1.1
    public class Singleton
    {
    private static final Singleton singleton = null;

    private Singleton()
    {
    }
    public static Singleton getInstance()
    {
    if (singleton== null)
    {
    synchronized (Singleton.class) {
    singleton= new Singleton();
    }
    }
    return singleton;
    }
    }

        嗯,使用了Java的synchronized方法,看起來(lái)不錯(cuò)哦。應(yīng)該沒(méi)有問(wèn)題了吧?!錯(cuò)!這還是有問(wèn)題!為什么呢?前面已經(jīng)說(shuō)過(guò),如果有多個(gè)線程同時(shí)通過(guò)(singleton== null)的條件檢查(因?yàn)樗麄儾⑿羞\(yùn)行),雖然我們的synchronized方法會(huì)幫助我們同步所有的線程,讓我們并行線程變成串行的一個(gè)一個(gè)去new,那不還是一樣的嗎?同樣會(huì)出現(xiàn)很多實(shí)例。嗯,確實(shí)如此!看來(lái),還得把那個(gè)判斷(singleton== null)條件也同步起來(lái)。于是,我們的Singleton再次升級(jí)成1.2版本,如下所示:

     // version 1.2
    public class Singleton
    {
    private static final Singleton singleton = null;

    private Singleton()
    {
    }
    public static Singleton getInstance()
    {
    synchronized (Singleton.class)
    {
    if (singleton== null)
    {
    singleton= new Singleton();
    }
    }
    return singleton;
    }
    }

        不錯(cuò)不錯(cuò),看似很不錯(cuò)了。在多線程下應(yīng)該沒(méi)有什么問(wèn)題了,不是嗎?的確是這樣的,1.2版的Singleton在多線程下的確沒(méi)有問(wèn)題了,因?yàn)槲覀兺搅怂械木€程。只不過(guò)嘛……,什么?!還不行?!是的,還是有點(diǎn)小問(wèn)題,我們本來(lái)只是想讓new這個(gè)操作并行就可以了,現(xiàn)在,只要是進(jìn)入getInstance()的線程都得同步啊,注意,創(chuàng)建對(duì)象的動(dòng)作只有一次,后面的動(dòng)作全是讀取那個(gè)成員變量,這些讀取的動(dòng)作不需要線程同步啊。這樣的作法感覺(jué)非常極端啊,為了一個(gè)初始化的創(chuàng)建動(dòng)作,居然讓我們達(dá)上了所有的讀操作,嚴(yán)重影響后續(xù)的性能啊!

        還得改!嗯,看來(lái),在線程同步前還得加一個(gè)(singleton== null)的條件判斷,如果對(duì)象已經(jīng)創(chuàng)建了,那么就不需要線程的同步了。OK,下面是1.3版的Singleton.

     // version 1.3
    public class Singleton
    {
    private static final Singleton singleton = null;

    private Singleton()
    {
    }
    public static Singleton getInstance()
    {
    if (singleton== null)
    {
    synchronized (Singleton.class)
    {
    if (singleton== null)
    {
    singleton= new Singleton();
    }
    }
    }
    return singleton;
    }
    }

        感覺(jué)代碼開(kāi)始變得有點(diǎn)羅嗦和復(fù)雜了,不過(guò),這可能是最不錯(cuò)的一個(gè)版本了,這個(gè)版本又叫“雙重檢查”Double-Check.下面是說(shuō)明:

        第一個(gè)條件是說(shuō),如果實(shí)例創(chuàng)建了,那就不需要同步了,直接返回就好了。

        不然,我們就開(kāi)始同步線程。

        第二個(gè)條件是說(shuō),如果被同步的線程中,有一個(gè)線程創(chuàng)建了對(duì)象,那么別的線程就不用再創(chuàng)建了。
    相當(dāng)不錯(cuò)啊,干得非常漂亮!請(qǐng)大家為我們的1.3版起立鼓掌!

        Singleton的其它問(wèn)題

        怎么?還有問(wèn)題?!當(dāng)然還有,請(qǐng)記住下面這條規(guī)則——“無(wú)論你的代碼寫得有多好,其只能在特定的范圍內(nèi)工作,超出這個(gè)范圍就要出Bug了”,這是“陳式第一定理”,呵呵。你能想一想還有什么情況會(huì)讓這個(gè)我們上面的代碼出問(wèn)題嗎?

        在C++下,我不是很好舉例,但是在Java的環(huán)境下,嘿嘿,還是讓我們來(lái)看看下面的一些反例和一些別的事情的討論(當(dāng)然,有些反例可能屬于鉆牛角尖,可能有點(diǎn)學(xué)院派,不過(guò)也不排除其實(shí)際可能性,就算是提個(gè)醒吧):

        其一、Class Loader.不知道你對(duì)Java的Class Loader熟悉嗎?“類裝載器”?!C++可沒(méi)有這個(gè)東西啊。這是Java動(dòng)態(tài)性的核心。顧名思義,類裝載器是用來(lái)把類(class)裝載進(jìn)JVM的。JVM規(guī)范定義了兩種類型的類裝載器:?jiǎn)?dòng)內(nèi)裝載器(bootstrap)和用戶自定義裝載器(user-defined class loader)。 在一個(gè)JVM中可能存在多個(gè)ClassLoader,每個(gè)ClassLoader擁有自己的NameSpace.一個(gè)ClassLoader只能擁有一個(gè)class對(duì)象類型的實(shí)例,但是不同的ClassLoader可能擁有相同的class對(duì)象實(shí)例,這時(shí)可能產(chǎn)生致命的問(wèn)題。如ClassLoaderA,裝載了類A的類型實(shí)例A1,而ClassLoaderB,也裝載了類A的對(duì)象實(shí)例A2.邏輯上講A1=A2,但是由于A1和A2來(lái)自于不同的ClassLoader,它們實(shí)際上是完全不同的,如果A中定義了一個(gè)靜態(tài)變量c,則c在不同的ClassLoader中的值是不同的。

        于是,如果咱們的Singleton 1.3版本如果面對(duì)著多個(gè)Class Loader會(huì)怎么樣?呵呵,多個(gè)實(shí)例同樣會(huì)被多個(gè)Class Loader創(chuàng)建出來(lái),當(dāng)然,這個(gè)有點(diǎn)牽強(qiáng),不過(guò)他確實(shí)存在。難道我們還要整出個(gè)1.4版嗎?可是,我們?cè)趺纯赡茉谖业腟ingleton類中操作Class Loader啊?是的,你根本不可能。在這種情況下,你能做的只有是——“保證多個(gè)Class Loader不會(huì)裝載同一個(gè)Singleton”。

        其二、序例化。如果我們的這個(gè)Singleton類是一個(gè)關(guān)于我們程序配置信息的類。我們需要它有序列化的功能,那么,當(dāng)反序列化的時(shí)候,我們將無(wú)法控制別人不多次反序列化。不過(guò),我們可以利用一下Serializable接口的readResolve()方法,比如:
     public class Singleton implements Serializable
    {
    ......
    ......
    protected Object readResolve()
    {
    return getInstance();
    }
    }

        其三、多個(gè)Java虛擬機(jī)。如果我們的程序運(yùn)行在多個(gè)Java的虛擬機(jī)中。什么?多個(gè)虛擬機(jī)?這是一種什么樣的情況啊。嗯,這種情況是有點(diǎn)極端,不過(guò)還是可能出現(xiàn),比如EJB或RMI之流的東西。要在這種環(huán)境下避免多實(shí)例,看來(lái)只能通過(guò)良好的設(shè)計(jì)或非技術(shù)來(lái)解決了。

        其四,volatile變量。關(guān)于volatile這個(gè)關(guān)鍵字所聲明的變量可以被看作是一種 “程度較輕的同步synchronized”;與 synchronized 塊相比,volatile 變量所需的編碼較少,并且運(yùn)行時(shí)開(kāi)銷也較少,但是它所能實(shí)現(xiàn)的功能也僅是synchronized的一部分。當(dāng)然,如前面所述,我們需要的Singleton只是在創(chuàng)建的時(shí)候線程同步,而后面的讀取則不需要同步。所以,volatile變量并不能幫助我們即能解決問(wèn)題,又有好的性能。而且,這種變量只能在JDK 1.5+版后才能使用。

        其五、關(guān)于繼承。是的,繼承于Singleton后的子類也有可能造成多實(shí)例的問(wèn)題。不過(guò),因?yàn)槲覀冊(cè)绨裇ingleton的構(gòu)造函數(shù)聲明成了私有的,所以也就杜絕了繼承這種事情。

        其六,關(guān)于代碼重用。也話我們的系統(tǒng)中有很多個(gè)類需要用到這個(gè)模式,如果我們?cè)诿恳粋€(gè)類都中有這樣的代碼,那么就顯得有點(diǎn)傻了。那么,我們是否可以使用一種方法,把這具模式抽象出去?在C++下這是很容易的,因?yàn)橛心0搴陀言€支持棧上分配內(nèi)存,所以比較容易一些(程序如下所示),Java下可能比較復(fù)雜一些,聰明的你知道怎么做嗎?

     template<CLASS T> class Singleton
    {
    public:
    static T& Instance()
    {
    static T theSingleInstance; //假設(shè)T有一個(gè)protected默認(rèn)構(gòu)造函數(shù)
    return theSingleInstance;
    }
    };

    class OnlyOne : public Singleton<ONLYONE>
    {
    friend class Singleton<ONLYONE>;
    int example_data;

    public:
    int GetExampleData() const {return example_data;}
    protected:
    OnlyOne(): example_data(42) {} // 默認(rèn)構(gòu)造函數(shù)
    OnlyOne(OnlyOne&) {}
    };

    int main( )
    {
    cout << OnlyOne::Instance().GetExampleData()<< endl;
    return 0;
    }
    原文:http://java.chinaitlab.com/base/780243_2.html

    posted on 2009-05-02 22:37 Werther 閱讀(299) 評(píng)論(1)  編輯  收藏 所屬分類: 10.Java

    評(píng)論:
    # re: 深入淺出單實(shí)例Singleton設(shè)計(jì)模式 2009-05-03 13:25 | 墻頭草


    這個(gè)也不錯(cuò)捏,雖然是C#的~~

    多線程Singleton單件模式


      回復(fù)  更多評(píng)論
      
    主站蜘蛛池模板: 国产精品永久免费视频| 免费国产a国产片高清| 羞羞视频免费网站在线看| 亚洲av无码一区二区三区观看| 久久精品国产亚洲一区二区三区| 成人免费福利电影| 无码A级毛片免费视频内谢| 一级做a爰片久久毛片免费陪 | 亚洲黄黄黄网站在线观看| 成人免费视频软件网站| 2019中文字幕在线电影免费| 久久九九免费高清视频| 麻豆一区二区三区蜜桃免费| 亚洲AV无码专区亚洲AV桃| 亚洲fuli在线观看| 亚洲美女视频一区| 亚洲AV日韩AV高潮无码专区| 中文字幕亚洲乱码熟女一区二区 | 亚洲综合校园春色| 亚洲综合一区二区| 久久精品a亚洲国产v高清不卡| 亚洲一区二区三区影院| 4338×亚洲全国最大色成网站| 国产免费观看黄AV片| 日韩激情无码免费毛片| 成人免费无码大片a毛片软件| 100000免费啪啪18免进| 国产精彩免费视频| 亚洲免费福利在线视频| 在线视频精品免费| 午夜性色一区二区三区免费不卡视频| 日韩av无码久久精品免费| 日本一卡精品视频免费| 91av免费观看| 99久久99这里只有免费费精品 | 亚洲精品午夜无码专区| 亚洲乱码精品久久久久..| 国产亚洲精品a在线观看app| 亚洲av一综合av一区| 亚洲av永久无码精品古装片| 内射干少妇亚洲69XXX|