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

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

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

    yunye 的 JavaBlog

    @see codemouse

    統(tǒng)計(jì)

    留言簿(1)

    閱讀排行榜

    評(píng)論排行榜

    Java單例模式(1)

    單例對(duì)象(Singleton)是一種常用的設(shè)計(jì)模式。在Java應(yīng)用中,單例對(duì)象能保證在一個(gè)JVM中,該對(duì)象只有一個(gè)實(shí)例存在。正是由于這個(gè)特 點(diǎn),單例對(duì)象通常作為程序中的存放配置信息的載體,因?yàn)樗鼙WC其他對(duì)象讀到一致的信息。例如在某個(gè)服務(wù)器程序中,該服務(wù)器的配置信息可能存放在數(shù)據(jù)庫(kù)或 文件中,這些配置數(shù)據(jù)由某個(gè)單例對(duì)象統(tǒng)一讀取,服務(wù)進(jìn)程中的其他對(duì)象如果要獲取這些配置信息,只需訪問(wèn)該單例對(duì)象即可。這種方式極大地簡(jiǎn)化了在復(fù)雜環(huán)境 下,尤其是多線程環(huán)境下的配置管理,但是隨著應(yīng)用場(chǎng)景的不同,也可能帶來(lái)一些同步問(wèn)題。

      本文將探討一下在多線程環(huán)境下,使用單例對(duì)象作配置信息管理時(shí)可能會(huì)帶來(lái)的幾個(gè)同步問(wèn)題,并針對(duì)每個(gè)問(wèn)題給出可選的解決辦法。

      問(wèn)題描述

      在多線程環(huán)境下,單例對(duì)象的同步問(wèn)題主要體現(xiàn)在兩個(gè)方面,單例對(duì)象的初始化和單例對(duì)象的屬性更新。

      本文描述的方法有如下假設(shè):

      1. 單例對(duì)象的屬性(或成員變量)的獲取,是通過(guò)單例對(duì)象的初始化實(shí)現(xiàn)的。也就是說(shuō),在單例對(duì)象初始化時(shí),會(huì)從文件或數(shù)據(jù)庫(kù)中讀取最新的配置信息。

      2. 其他對(duì)象不能直接改變單例對(duì)象的屬性,單例對(duì)象屬性的變化來(lái)源于配置文件或配置數(shù)據(jù)庫(kù)數(shù)據(jù)的變化。

      1.1 單例對(duì)象的初始化

      首先,討論一下單例對(duì)象的初始化同步。單例模式的通常處理方式是,在對(duì)象中有一個(gè)靜態(tài)成員變量,其類型就是單例類型本身;如果該變量為null,則創(chuàng)建該單例類型的對(duì)象,并將該變量指向這個(gè)對(duì)象;如果該變量不為null,則直接使用該變量。

      其過(guò)程如下面代碼所示:

    public class GlobalConfig {
    private static GlobalConfig instance = null;
    private Vector properties = null;
    private GlobalConfig() {
    //Load configuration information from DB or file
    //Set values for properties
    }
    public static GlobalConfig getInstance() {
    if (instance == null) {
    instance = new GlobalConfig();
    }
    return instance;
    }
    public Vector getProperties() {
    return properties;
    }
    }




    這種處理方式在單線程的模式下可以很好的運(yùn)行;但是在多線程模式下,可能產(chǎn)生問(wèn)題。如果第一個(gè)線程發(fā)現(xiàn)成員變量為null,準(zhǔn)備創(chuàng)建對(duì)象;這是第二 個(gè)線程同時(shí)也發(fā)現(xiàn)成員變量為null,也會(huì)創(chuàng)建新對(duì)象。這就會(huì)造成在一個(gè)JVM中有多個(gè)單例類型的實(shí)例。如果這個(gè)單例類型的成員變量在運(yùn)行過(guò)程中變化,會(huì) 造成多個(gè)單例類型實(shí)例的不一致,產(chǎn)生一些很奇怪的現(xiàn)象。例如,某服務(wù)進(jìn)程通過(guò)檢查單例對(duì)象的某個(gè)屬性來(lái)停止多個(gè)線程服務(wù),如果存在多個(gè)單例對(duì)象的實(shí)例,就 會(huì)造成部分線程服務(wù)停止,部分線程服務(wù)不能停止的情況。

      1.2 單例對(duì)象的屬性更新

      通常,為了實(shí)現(xiàn)配置信息的實(shí)時(shí)更新,會(huì)有一個(gè)線程不停檢測(cè)配置文件或配置數(shù)據(jù)庫(kù)的內(nèi)容,一旦發(fā)現(xiàn)變化,就更新到單例對(duì)象的屬性中。在更新這些信 息的時(shí)候,很可能還會(huì)有其他線程正在讀取這些信息,造成意想不到的后果。還是以通過(guò)單例對(duì)象屬性停止線程服務(wù)為例,如果更新屬性時(shí)讀寫(xiě)不同步,可能訪問(wèn)該 屬性時(shí)這個(gè)屬性正好為空(null),程序就會(huì)拋出異常。

      解決方法

      2.1 單例對(duì)象的初始化同步

      對(duì)于初始化的同步,可以通過(guò)如下代碼所采用的方式解決。

      public class GlobalConfig {
    private static GlobalConfig instance = null;
    private Vector properties = null;
    private GlobalConfig() {
    //Load configuration information from DB or file
    //Set values for properties
    }
    private static synchronized void syncInit() {
    if (instance == null) {
    instance = new GlobalConfig();
    }
    }
    public static GlobalConfig getInstance() {
    if (instance == null) {
    syncInit();
    }
    return instance;
    }
    public Vector getProperties() {
    return properties;
    }
    }

      這種處理方式雖然引入了同步代碼,但是因?yàn)檫@段同步代碼只會(huì)在最開(kāi)始的時(shí)候執(zhí)行一次或多次,所以對(duì)整個(gè)系統(tǒng)的性能不會(huì)有影響。

    2.2 單例對(duì)象的屬性更新同步

      為了解決第2個(gè)問(wèn)題,有兩種方法:

      1,參照讀者/寫(xiě)者的處理方式

      設(shè)置一個(gè)讀計(jì)數(shù)器,每次讀取配置信息前,將計(jì)數(shù)器加1,讀完后將計(jì)數(shù)器減1.只有在讀計(jì)數(shù)器為0時(shí),才能更新數(shù)據(jù),同時(shí)要阻塞所有讀屬性的調(diào)用。代碼如下。

      public class GlobalConfig {
    private static GlobalConfig instance;
    private Vector properties = null;
    private boolean isUpdating = false;
    private int readCount = 0;
    private GlobalConfig() {
    //Load configuration information from DB or file
    //Set values for properties
    }
    private static synchronized void syncInit() {
    if (instance == null) {
    instance = new GlobalConfig();
    }
    }
    public static GlobalConfig getInstance() {
    if (instance==null) {
    syncInit();
    }
    return instance;
    }
    public synchronized void update(String p_data) {
    syncUpdateIn();
    //Update properties
    }
    private synchronized void syncUpdateIn() {
    while (readCount > 0) {
    try {
    wait();
    } catch (Exception e) {
    }
    }
    }
    private synchronized void syncReadIn() {
    readCount++;
    }
    private synchronized void syncReadOut() {
    readCount--;
    notifyAll();
    }
    public Vector getProperties() {
    syncReadIn();
    //Process data
    syncReadOut();
    return properties;
    }
    }

      2,采用"影子實(shí)例"的辦法

      具體說(shuō),就是在更新屬性時(shí),直接生成另一個(gè)單例對(duì)象實(shí)例,這個(gè)新生成的單例對(duì)象實(shí)例將從數(shù)據(jù)庫(kù)或文件中讀取最新的配置信息;然后將這些配置信息直接賦值給舊單例對(duì)象的屬性。如下面代碼所示。

      public class GlobalConfig {
    private static GlobalConfig instance = null;
    private Vector properties = null;
    private GlobalConfig() {
    //Load configuration information from DB or file
    //Set values for properties
    }
    private static synchronized void syncInit() {
    if (instance = null) {
    instance = new GlobalConfig();
    }
    }
    public static GlobalConfig getInstance() {
    if (instance = null) {
    syncInit();
    }
    return instance;
    }
    public Vector getProperties() {
    return properties;
    }
    public void updateProperties() {
    //Load updated configuration information by new a GlobalConfig object
    GlobalConfig shadow = new GlobalConfig();
    properties = shadow.getProperties();
    }
    }

      注意:在更新方法中,通過(guò)生成新的GlobalConfig的實(shí)例,從文件或數(shù)據(jù)庫(kù)中得到最新配置信息,并存放到properties屬性中。

      上面兩個(gè)方法比較起來(lái),第二個(gè)方法更好,首先,編程更簡(jiǎn)單;其次,沒(méi)有那么多的同步操作,對(duì)性能的影響也不大。

    posted on 2008-06-05 12:43 yunye 閱讀(300) 評(píng)論(0)  編輯  收藏 所屬分類: 其他


    只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 亚洲成a人片在线观看播放| 亚洲一本一道一区二区三区| 中国xxxxx高清免费看视频| 亚洲高清视频在线| 亚洲精品麻豆av| 18观看免费永久视频| 亚洲av无码成人精品区一本二本| 伊伊人成亚洲综合人网7777| 精品无码人妻一区二区免费蜜桃| 国产天堂亚洲精品| 亚洲黄色片在线观看| 四虎永久精品免费观看| 亚洲免费视频在线观看| 色婷婷亚洲一区二区三区| 99亚洲精品高清一二区| 成人永久免费福利视频网站| 亚洲一区二区在线免费观看| 久久水蜜桃亚洲AV无码精品| 久久亚洲精品成人| 又黄又爽一线毛片免费观看 | 免费中文字幕视频| 亚洲精品自在线拍| 国产成人精品久久亚洲高清不卡 | 亚洲免费中文字幕| 中文字幕不卡高清免费| 亚洲精品永久在线观看| 亚洲视频免费观看| 久久青青草原亚洲av无码| 日韩免费三级电影| 久久国产免费福利永久| 在线免费视频你懂的| 精品久久亚洲一级α| 亚洲AV无码久久久久网站蜜桃| 亚洲国产另类久久久精品黑人| 国产一区在线观看免费| 美女裸身网站免费看免费网站| 99久久国产精品免费一区二区| 日韩在线一区二区三区免费视频 | 亚洲一区二区三区91| 亚洲天天做日日做天天看 | 亚洲AV网一区二区三区|