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

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

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

    cuiyi's blog(崔毅 crazycy)

    記錄點滴 鑒往事之得失 以資于發展
    數據加載中……

    單例模式(SingLeton Pattern)的誤區

    單例(SingLeton)故名思義就是在一個JVM運行中只有一個對象存在;請你務必注意到是在一個JVM虛擬機內。

    今天一個朋友問過這樣一個問題:為什么他的單例每次都進入構造函數,程序如下:

    public?class?ServerThread?implements?Runnable{

    ?????
    private?static?ServerThread?instance?=?null;??

    ?????
    private?ServerThread()?{

    ?????????
    try?{

    ?????????????
    if?(socket?==?null)?{

    ?????????????????socket?
    =?new?DatagramSocket(Constants.SERVER_PORT);

    ?????????????}

    ??????????}?
    catch?(Exception?e)?{

    ?????????????????e.printStackTrace();

    ???????????}

    ???????}

    ?????
    public?static?final?ServerThread?getInstance()?{

    ????????
    if?(instance?==?null)?{
    ???????????System.out.println(
    "instance?is?null?new?generate.");
    ???????????instance?
    =?new?ServerThread();
    ????????}
    ????????
    return?instance;

    ??????}

    ????
    public?Thread?getThreadInstance()?{

    ????????
    if?(threadInstance?==?null)?{

    ????????????threadInstance?
    =?new?Thread(instance);
    ????????}
    ????????
    return?threadInstance;
    ????}

    。。。。。。。。

    }

    public?class?Main?{

    ??????main函數有servTr?
    =?ServerThread.getInstance().getThreadInstance();一句

    代碼沒有問題吧;為什么他的單例每次都進入構造函數呢?

    細問之下才知道了他啟動了兩次Main類;啟動一個Main類便在一個JVM,兩次的單例怎么能是同一個呢?!

    記住:是在同一個JVM中唯一,不是在一個物理內存中唯一。當然后者不是不能做到的,分布式對象嘛,呵呵。


    第二點就是:單例的構造:

    目前方式多種,我認為只有兩種是正確的:

    第一:private final static DaoFactory instance = new DaoFactory();

    第二:

    private?static?DaoFactory?instance?=?null;

    ??????
    private?Properties?props?=?null;

    ???????
    private?Map?daos?=?null;

    ??????
    private?DaoFactory()?{

    ???????????props?
    =?new?Properties();

    ???????????daos?
    =?new?HashMap();

    ??????}

    ?????

    ??????
    public?static?DaoFactory?getInstance()?{

    ???????????
    while?(null?==?instance)?{

    ?????????????????
    synchronized(DaoFactory.class)?{

    ??????????????????????
    if?(null?==?instance)?{

    ????????????????????????????instance?
    =?new?DaoFactory();

    ????????????????????????????instance.initDaoFactroy();

    ??????????????????????}

    ?????????????????}

    ???????????}

    ???????????
    return?instance;

    ??????}


    看清楚了,這里用的是while;不是if

    為什么不能用if呢?下面的一個例子說明

    public?class?DomainFactory?{

    ??????
    private?List?provinces;
    ?
    ???????????
    private?Map?domains;

    ??????
    private?static?DomainFactory?instance;

    ??????
    private?DomainFactory()?{

    ???????????generateDomainTree();

    ??????}

    ??????
    public?static?DomainFactory?getInstance()?{

    ???????????
    if?(null?==?instance)?{

    ?????????????????
    synchronized?(DomainFactory.class)?{

    ??????????????????????
    if?(null?==?instance)?{

    ????????????????????????????instance?
    =?new?DomainFactory();

    ??????????????????????}

    ?????????????????}

    ???????????}

    ???????????
    return?instance;

    ??????}

    ??????
    private?void?generateDomainTree()?{

    。。。。。

    }


    ?

    public?class?CategoryFactory?{

    ??????
    private?Map?map;?????

    ??????
    private?static?CategoryFactory?instance;
    ?????

    ??????
    private?CategoryFactory()?{

    ???????????map?
    =?new?HashMap();

    ???????????generateCategoryTree();

    ??????}?????

    ??????
    public?static?CategoryFactory?getInstance()?{

    ???????????
    if?(null?==?instance)?{

    ?????????????????
    synchronized?(CategoryFactory.class)?{

    ??????????????????????
    if?(null?==?instance)?{

    ????????????????????????????instance?
    =?new?CategoryFactory();

    ??????????????????????}

    ?????????????????}

    ???????????}

    ???????????
    return?instance;

    ??????}?????

    ??????
    private?void?generateCategoryTree()?{

    。。。。。。

    }

    ?

    public?class?SearchAction?extends?DispatchAction?{

    ??????
    public?ActionForward?getCatalogData(ActionMapping?mapping,?ActionForm?form,

    ?????????????????HttpServletRequest?request,?HttpServletResponse?response)?{

    ???????????DomainObject?domainObject?
    =?new?DomainObject();

    ???????????domainObject.setCity(
    "b");

    ???????????request.getSession().setAttribute(
    "domainObject",?domainObject);

    ???????????request.setAttribute(
    "domains",?DomainFactory.getInstance().getCity(domainObject.getCity()));

    ???????????
    return?mapping.findForward("left");

    ??????}????
    ?

    ??????
    public?ActionForward?getCatalogDataCategory(ActionMapping?mapping,?ActionForm?form,

    ?????????????????HttpServletRequest?request,?HttpServletResponse?response)?{

    ???????????request.setAttribute(
    "productCategories",?CategoryFactory.getInstance().getRootProductCategories());

    ???????????
    return?mapping.findForward("body");

    ??????}

    <frameset?rows="80,668*"?cols="*"?frameborder="no"?border="0"?framespacing="0">

    ????
    <frame?name="header"?src="./search_header.jsp"?scrolling="no"?title="header"?noresize="noresize">

    ????
    <frameset?cols="180,*"?frameborder="yes"?border="0"?framespacing="0">

    ???????
    <frame?name="left"?scrolling="no"?src="search.html?method=getCatalogData"?target="_self"?noresize="noresize">

    ???????
    <frame?name="body"?scrolling="yes"?src="search.html?method=getCatalogDataCategory"?scrolling="yes"?target="_self"?noresize="noresize">
    ??
    </frameset>
    </frameset>

    用if 出錯了吧?為什么,同時進入了if(null == instance)的判斷,然后爭奪鎖;結果爭奪不到的只能在爭奪到后容易出現問題,具體這里說不清楚,希望明白人跟貼進一步討論之

    posted on 2006-07-15 00:02 crazycy 閱讀(2537) 評論(13)  編輯  收藏 所屬分類: Design Pattern、JEE Pattern

    評論

    # re: 單例模式(SingLeton Pattern)的誤區  回復  更多評論   

    改為
    public synchronized static DaoFactory getInstance() {
    if(instance == null) {
    instance = new DaoFactory();
    instance.initDaoFactroy();
    }
    }
    }
    2006-07-15 08:00 | badqiu

    # re: 單例模式(SingLeton Pattern)的誤區  回復  更多評論   

    我想問問,在一個web server,比如tomcat下,放兩個application。
    在這兩個application中都包含有同一個單實例的class。那么這兩個單實例會互相有影響么?為什么在web系統中很少見人使用單實例,實際的例子就是spring取對象的方式,直接做一個單實例封裝一下就可以在系統內方便的取對象了,為什么還要用WebApplicationContextUtils.getRequiredWebApplicationContext(context)的方式來取,我看代碼spring 是把啟動時加載的配置信息放在ServletContext里,為什么不直接放在一個單實例里取值還方便,對單實例一直有疑惑,還請老兄賜教
    2006-07-15 08:16 | mixlee

    # re: 單例模式(SingLeton Pattern)的誤區  回復  更多評論   

    @mixlee
    兩個application的classpath不一樣,放在WEB-INF里面的lib是不能共享的,spring的ApplicationContext是跟具體的webapp相關的,當然不能做成全局的單例,只能做成一個ServletContext里面的單例
    2006-07-15 12:03 | quaff

    # re: 單例模式(SingLeton Pattern)的誤區  回復  更多評論   

    關于單例
    懶漢和餓漢式的是最安全的.這里有篇文章不妨參考一下
    http://www-128.ibm.com/developerworks/java/library/j-dcl.html?dwzone=java
    2006-07-15 12:39 | binge

    # re: 單例模式(SingLeton Pattern)的誤區  回復  更多評論   

    @badqiu
    呵呵

    多謝多謝

    今天我用while也遇到了和if一樣的問題
    看樣子,的確是單例實現方式的問題
    現在我用你推薦的方案改進一下
    2006-07-15 16:19 | crazycy

    # re: 單例模式(SingLeton Pattern)的誤區  回復  更多評論   

    @binge
    我用的就是你推薦的文章的Double-checked locking哦

    奇怪了 我這個地方是同時搶占;而且是肯定發生的;

    哎...以前一直這么用,只是取instance的線程同時搶占的幾率小,呵呵,問題的深入解決看來還需要多過河才行(多過河找到不濕腳的辦法,呵呵)啊
    2006-07-15 16:23 | crazycy

    # re: 單例模式(SingLeton Pattern)的誤區  回復  更多評論   

    @quaff
    既然兩個沒影響,那做成單例有什么不可,反正各自加載各自的配置文件,互不影響。
    2006-07-15 21:25 | mixlee

    # re: 單例模式(SingLeton Pattern)的誤區  回復  更多評論   

    @crazycy
    nono,文章寫到:
    The issue of the failure of double-checked locking is not due to implementation bugs in JVMs but to the current Java platform memory model. The memory model allows what is known as "out-of-order writes" and is a prime reason why this idiom fails.

    文章中說,基于java的內存模型,DCL并不是最安全的.最安全的是餓漢 和懶漢.
    當然,懶漢很影響效率.
    2006-07-15 22:28 | binge

    # re: 單例模式(SingLeton Pattern)的誤區  回復  更多評論   

    記住:是在同一個JVM中唯一,不是在一個物理內存中唯一。當然后者不是不能做到的,分布式對象嘛,呵呵。


    看了很受啟發,想問一下,如果我希望在一個物理內存中唯一,甚至在多個應用服務器的cluster環境中唯一,有什么方法嗎?
    2006-08-24 14:25 | merrymei

    # re: 單例模式(SingLeton Pattern)的誤區  回復  更多評論   

    @merrymei

    好像也提供不出解決方案.......
    2006-09-01 10:51 | crazycy

    # re: 單例模式(SingLeton Pattern)的誤區  回復  更多評論   

    DCL方式在java里是行不通的。 希望不要誤導別人
    2006-09-20 14:42 | freshman

    # re: 單例模式(SingLeton Pattern)的誤區  回復  更多評論   

    @freshman
    接受建議
    2006-09-20 22:23 | crazycy

    # re: 單例模式(SingLeton Pattern)的誤區  回復  更多評論   

    使用 synchronized 關鍵字就可以解決鎖爭奪的問題
    2006-10-11 09:44 | www.坑你.net
    主站蜘蛛池模板: 亚洲色四在线视频观看| 国产成人综合亚洲亚洲国产第一页 | 亚洲精品无码久久久久牙蜜区| 99久久久国产精品免费牛牛四川| 亚洲色婷婷六月亚洲婷婷6月| 黄色网页在线免费观看| 亚洲国产精品第一区二区三区| 粉色视频成年免费人15次| 免费观看国产精品| 成人精品综合免费视频| 久久精品国产精品亚洲人人 | 亚洲国产天堂久久久久久| 成在线人直播免费视频| 亚洲尤码不卡AV麻豆| 国内精品免费视频精选在线观看| 亚洲狠狠久久综合一区77777| 亚洲无砖砖区免费| 在线观看日本亚洲一区| 国产一区二区三区在线免费| 免费无码专区毛片高潮喷水| 亚洲一区二区三区影院 | 成人特黄a级毛片免费视频| 亚洲精品国产av成拍色拍| 亚洲中文字幕久久久一区| 免费观看国产精品| 男人天堂免费视频| 亚洲中文字幕丝袜制服一区| 拍拍拍无挡视频免费观看1000| 亚洲天堂一区二区| 国产精品成人四虎免费视频| 国产免费人成视频在线播放播 | 亚洲六月丁香婷婷综合| 免费观看美女裸体网站| 精品久久久久久亚洲精品| 大香人蕉免费视频75| fc2成年免费共享视频18| 亚洲综合在线观看视频| 在线播放免费人成视频在线观看| 特级毛片在线大全免费播放| 97se亚洲综合在线| 免费播放春色aⅴ视频|