<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
    主站蜘蛛池模板: 亚洲av中文无码乱人伦在线咪咕| 久久精品亚洲综合专区| 日韩av无码免费播放| 亚洲一区二区三区91| 亚洲av无码av制服另类专区| 免费看AV毛片一区二区三区| 毛片在线播放免费观看| 91福利免费网站在线观看| 校园亚洲春色另类小说合集| 亚洲真人无码永久在线观看| 亚洲欧洲日韩国产| 亚洲成人黄色在线观看| 91亚洲国产成人久久精品网站| 亚洲中文字幕久久精品无码APP| 四虎免费影院4hu永久免费| 免费黄色大片网站| 免费国产成人高清视频网站| 精品久久免费视频| 亚洲视频一区二区| 亚洲乱码日产一区三区| 亚洲国产高清视频| 亚洲制服丝袜一区二区三区| 中文字幕亚洲情99在线| 日韩国产精品亚洲а∨天堂免| 国产成人亚洲午夜电影| 美女网站在线观看视频免费的 | 成年女人午夜毛片免费视频| 国内精品免费视频自在线| 亚洲一区二区精品视频| 久久久久久亚洲AV无码专区| 亚洲变态另类一区二区三区| 老司机免费午夜精品视频| 一区二区在线免费视频| 亚洲免费闲人蜜桃| 亚洲片国产一区一级在线观看 | 91情侣在线精品国产免费| 国产成人免费a在线视频色戒| 国产亚洲精品a在线无码| 亚洲乱码卡一卡二卡三| 中国一级毛片视频免费看| 成年男女男精品免费视频网站 |