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

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

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

    cuiyi's blog(崔毅 crazycy)

    記錄點(diǎn)滴 鑒往事之得失 以資于發(fā)展
    數(shù)據(jù)加載中……

    單例模式(SingLeton Pattern)的誤區(qū)

    單例(SingLeton)故名思義就是在一個(gè)JVM運(yùn)行中只有一個(gè)對(duì)象存在;請(qǐng)你務(wù)必注意到是在一個(gè)JVM虛擬機(jī)內(nèi)。

    今天一個(gè)朋友問過這樣一個(gè)問題:為什么他的單例每次都進(jìn)入構(gòu)造函數(shù),程序如下:

    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函數(shù)有servTr?
    =?ServerThread.getInstance().getThreadInstance();一句

    代碼沒有問題吧;為什么他的單例每次都進(jìn)入構(gòu)造函數(shù)呢?

    細(xì)問之下才知道了他啟動(dòng)了兩次Main類;啟動(dòng)一個(gè)Main類便在一個(gè)JVM,兩次的單例怎么能是同一個(gè)呢?!

    記住:是在同一個(gè)JVM中唯一,不是在一個(gè)物理內(nèi)存中唯一。當(dāng)然后者不是不能做到的,分布式對(duì)象嘛,呵呵。


    第二點(diǎn)就是:?jiǎn)卫臉?gòu)造:

    目前方式多種,我認(rèn)為只有兩種是正確的:

    第一: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呢?下面的一個(gè)例子說明

    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 出錯(cuò)了吧?為什么,同時(shí)進(jìn)入了if(null == instance)的判斷,然后爭(zhēng)奪鎖;結(jié)果爭(zhēng)奪不到的只能在爭(zhēng)奪到后容易出現(xiàn)問題,具體這里說不清楚,希望明白人跟貼進(jìn)一步討論之

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

    評(píng)論

    # re: 單例模式(SingLeton Pattern)的誤區(qū)  回復(fù)  更多評(píng)論   

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

    # re: 單例模式(SingLeton Pattern)的誤區(qū)  回復(fù)  更多評(píng)論   

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

    # re: 單例模式(SingLeton Pattern)的誤區(qū)  回復(fù)  更多評(píng)論   

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

    # re: 單例模式(SingLeton Pattern)的誤區(qū)  回復(fù)  更多評(píng)論   

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

    # re: 單例模式(SingLeton Pattern)的誤區(qū)  回復(fù)  更多評(píng)論   

    @badqiu
    呵呵

    多謝多謝

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

    # re: 單例模式(SingLeton Pattern)的誤區(qū)  回復(fù)  更多評(píng)論   

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

    奇怪了 我這個(gè)地方是同時(shí)搶占;而且是肯定發(fā)生的;

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

    # re: 單例模式(SingLeton Pattern)的誤區(qū)  回復(fù)  更多評(píng)論   

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

    # re: 單例模式(SingLeton Pattern)的誤區(qū)  回復(fù)  更多評(píng)論   

    @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的內(nèi)存模型,DCL并不是最安全的.最安全的是餓漢 和懶漢.
    當(dāng)然,懶漢很影響效率.
    2006-07-15 22:28 | binge

    # re: 單例模式(SingLeton Pattern)的誤區(qū)  回復(fù)  更多評(píng)論   

    記住:是在同一個(gè)JVM中唯一,不是在一個(gè)物理內(nèi)存中唯一。當(dāng)然后者不是不能做到的,分布式對(duì)象嘛,呵呵。


    看了很受啟發(fā),想問一下,如果我希望在一個(gè)物理內(nèi)存中唯一,甚至在多個(gè)應(yīng)用服務(wù)器的cluster環(huán)境中唯一,有什么方法嗎?
    2006-08-24 14:25 | merrymei

    # re: 單例模式(SingLeton Pattern)的誤區(qū)  回復(fù)  更多評(píng)論   

    @merrymei

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

    # re: 單例模式(SingLeton Pattern)的誤區(qū)  回復(fù)  更多評(píng)論   

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

    # re: 單例模式(SingLeton Pattern)的誤區(qū)  回復(fù)  更多評(píng)論   

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

    # re: 單例模式(SingLeton Pattern)的誤區(qū)  回復(fù)  更多評(píng)論   

    使用 synchronized 關(guān)鍵字就可以解決鎖爭(zhēng)奪的問題
    2006-10-11 09:44 | www.坑你.net
    主站蜘蛛池模板: 亚洲中文字幕无码爆乳| 精品国产亚洲一区二区三区在线观看 | 亚洲综合激情九月婷婷| 精品在线免费观看| 在线看片无码永久免费视频| 国产精品久久香蕉免费播放| 亚洲AV成人影视在线观看| 青青操免费在线观看| 国产AV无码专区亚洲AV手机麻豆| 亚洲精品国产精品国自产网站| 精精国产www视频在线观看免费| 亚洲日本在线观看视频| 高清永久免费观看| 国产高清在线精品免费软件| 亚洲成aⅴ人片久青草影院按摩| 久久aⅴ免费观看| 亚洲精品国产电影午夜| 免费看国产精品3a黄的视频| 亚洲国产成人久久精品动漫 | 四虎永久成人免费影院域名| 亚洲国产一区国产亚洲| 天天影视色香欲综合免费| 亚洲卡一卡二卡乱码新区| 国产精品免费视频网站| 一级毛片在播放免费| 亚洲一区影音先锋色资源| 无码国产精品一区二区免费式影视| 亚洲人成人伊人成综合网无码| 亚洲第一区在线观看| 午夜不卡久久精品无码免费 | 欧美日韩亚洲精品| 狠狠亚洲婷婷综合色香五月排名| 三年片在线观看免费观看大全动漫| 亚洲欧洲春色校园另类小说| 成人免费无码精品国产电影| 国产高清对白在线观看免费91| 亚洲精品在线不卡| 一本久久综合亚洲鲁鲁五月天| 亚洲爆乳大丰满无码专区| 亚洲国产综合无码一区二区二三区| 无码av免费一区二区三区试看|