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

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

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

    yunye 的 JavaBlog

    @see codemouse

    統計

    留言簿(1)

    閱讀排行榜

    評論排行榜

    Java單例模式(1)

    單例對象(Singleton)是一種常用的設計模式。在Java應用中,單例對象能保證在一個JVM中,該對象只有一個實例存在。正是由于這個特 點,單例對象通常作為程序中的存放配置信息的載體,因為它能保證其他對象讀到一致的信息。例如在某個服務器程序中,該服務器的配置信息可能存放在數據庫或 文件中,這些配置數據由某個單例對象統一讀取,服務進程中的其他對象如果要獲取這些配置信息,只需訪問該單例對象即可。這種方式極大地簡化了在復雜環境 下,尤其是多線程環境下的配置管理,但是隨著應用場景的不同,也可能帶來一些同步問題。

      本文將探討一下在多線程環境下,使用單例對象作配置信息管理時可能會帶來的幾個同步問題,并針對每個問題給出可選的解決辦法。

      問題描述

      在多線程環境下,單例對象的同步問題主要體現在兩個方面,單例對象的初始化和單例對象的屬性更新。

      本文描述的方法有如下假設:

      1. 單例對象的屬性(或成員變量)的獲取,是通過單例對象的初始化實現的。也就是說,在單例對象初始化時,會從文件或數據庫中讀取最新的配置信息。

      2. 其他對象不能直接改變單例對象的屬性,單例對象屬性的變化來源于配置文件或配置數據庫數據的變化。

      1.1 單例對象的初始化

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

      其過程如下面代碼所示:

    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;
    }
    }




    這種處理方式在單線程的模式下可以很好的運行;但是在多線程模式下,可能產生問題。如果第一個線程發現成員變量為null,準備創建對象;這是第二 個線程同時也發現成員變量為null,也會創建新對象。這就會造成在一個JVM中有多個單例類型的實例。如果這個單例類型的成員變量在運行過程中變化,會 造成多個單例類型實例的不一致,產生一些很奇怪的現象。例如,某服務進程通過檢查單例對象的某個屬性來停止多個線程服務,如果存在多個單例對象的實例,就 會造成部分線程服務停止,部分線程服務不能停止的情況。

      1.2 單例對象的屬性更新

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

      解決方法

      2.1 單例對象的初始化同步

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

      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;
    }
    }

      這種處理方式雖然引入了同步代碼,但是因為這段同步代碼只會在最開始的時候執行一次或多次,所以對整個系統的性能不會有影響。

    2.2 單例對象的屬性更新同步

      為了解決第2個問題,有兩種方法:

      1,參照讀者/寫者的處理方式

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

      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,采用"影子實例"的辦法

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

      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();
    }
    }

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

      上面兩個方法比較起來,第二個方法更好,首先,編程更簡單;其次,沒有那么多的同步操作,對性能的影響也不大。

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


    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: 无套内射无矿码免费看黄| 免费a级毛片无码a∨性按摩| 午夜不卡AV免费| 亚洲国产情侣一区二区三区| 国产亚洲av片在线观看18女人| 黄色片在线免费观看| 日本三级在线观看免费| 美女黄色免费网站| 亚洲一级特黄特黄的大片| 亚洲a一级免费视频| 中文国产成人精品久久亚洲精品AⅤ无码精品| www视频免费看| 久久久久国色av免费看| 中文日本免费高清| 羞羞漫画在线成人漫画阅读免费| 7777久久亚洲中文字幕| 亚洲国产精品成人精品小说| 亚洲av日韩av激情亚洲| 国产亚洲婷婷香蕉久久精品 | 亚洲毛片αv无线播放一区| 国产在线观看免费完整版中文版| 久久WWW免费人成人片| 99热这里只有精品免费播放| 国产麻豆一精品一AV一免费| 中文字幕免费播放| a毛片成人免费全部播放| 无码人妻一区二区三区免费视频| 国产精品亚洲va在线观看| 亚洲av无码一区二区三区天堂 | 成人女人A级毛片免费软件| 最近2019中文字幕免费直播| 久久国产精品免费专区| 最近免费mv在线观看动漫| 男人j进入女人j内部免费网站 | 亚洲精品V欧洲精品V日韩精品| 亚洲国产黄在线观看| 亚洲阿v天堂在线2017免费| 亚洲免费无码在线| 亚洲永久精品ww47| 亚洲AV无码码潮喷在线观看| 亚洲AV人无码激艳猛片|