<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 閱讀(2538) 評論(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
    主站蜘蛛池模板: 成人免费大片免费观看网站| 亚洲精品人成无码中文毛片| 亚洲久热无码av中文字幕| 免费a级黄色毛片| 日本高清高色视频免费| 亚洲中文字幕一二三四区| 亚洲女人被黑人巨大进入| 在线观看永久免费| 无码日韩人妻AV一区免费l| 亚洲av综合av一区| 日韩成全视频观看免费观看高清 | 97无码人妻福利免费公开在线视频| 亚洲码在线中文在线观看| 日本一道综合久久aⅴ免费| 免费av片在线观看网站| 日韩国产欧美亚洲v片| 日韩精品内射视频免费观看| 国产精品亚洲一区二区无码| 亚洲综合久久综合激情久久 | 久久精品亚洲福利| 91视频国产免费| 最近2019中文免费字幕在线观看 | 亚洲黄片手机免费观看| 男人天堂2018亚洲男人天堂| 亚洲AV无码久久| vvvv99日韩精品亚洲| 免费在线看v网址| 免费在线观影网站| 色妞www精品视频免费看| 亚洲av永久无码精品三区在线4 | 亚洲天堂男人影院| 亚洲av综合色区| 在线观看亚洲成人| 日本特黄a级高清免费大片| 免费观看激色视频网站(性色)| a级毛片在线免费观看| 免费一区二区无码视频在线播放 | 国产性爱在线观看亚洲黄色一级片| 在线观看免费a∨网站| 希望影院高清免费观看视频| 国产午夜精品免费一区二区三区|