創(chuàng)建模式之Singleton——單例模式

          1、簡介
                  作為對象的創(chuàng)建模式,單例模式確保某個類只有一個實例,而且自行實例化,并向系統提供這個實例,這個類稱為單例類。他有三個要點:
                  只能有一個實例
                  自行創(chuàng)建這個實例
                  自行向系統提供這個實例

          2、使用場景及能解決的問題
                  當你只需要一個類實例時,Singleton才真正有用;如果類擁有幾個實例,使用Singleton就不再適用。

              設計系統時,通常希望控制對象的用法,防止用戶復制對象或建立新實例。例如,你可以使用它創(chuàng)建一個連接池,每次程序需要往數據庫中寫入內容時才創(chuàng)建一個新連接的做法并不明智;相反,一個或一組已經在池中的連接就可以使用Singleton模式實例化。

                  Singleton模式常常和工廠方法模式一同使用,創(chuàng)建一個系統級資源,使用這個資源的代碼并不知道它的特殊類型。抽象窗口工具包(AWT)就是組合使用這兩個模式的典型例子。在GUI應用程序中,對每個應用程序實例,你一般只需要一個圖形元素的實例,如打印(Print)對話框或OK按鈕。

          3、類圖


          4、單例模式的運行機制
                  Singleton是一個無法實例化的對象。這種設計模式暗示,在任何時候,只能由JVM創(chuàng)建一個Singleton
          (對象)實例。如果實例不存在,你通過創(chuàng)建類的新實例的方法建立一個類來執(zhí)行這個模式;如果存在類的一個實例,就只會返回那個對象的一個引用。
              下面看看單例模式的幾種實現方式:
             
           
              方式1:
              

          public class Singleton {

            
          //注意構造方法必須是私有的

                private Singleton(){}


            
          //在自己內部定義自己一個實例,是不是很奇怪?
            
          //注意這是private 只供內部調用


            private static Singleton instance = new Singleton();

            
          //這里提供了一個供外部訪問本class的靜態(tài)方法,可以直接訪問  

            public static Singleton getInstance() 
          {
              
          return instance;   
             }
           
          }
           


              方式2:

          public class Singleton 
            
          private static Singleton instance = null;

            
          public static synchronized Singleton getInstance() 
          {

                
          //這個方法比上面有所改進,不用每次都進行生成對象,只是第一次     
                
          //使用時生成實例!

                if (instance==null)
                  instance=
          new Singleton();
                      
          return
           instance;
                }
           
                 }





              方式2就是我們說的:滯后初始化(Lazy Initialization)。為什么會有滯后初始化這種實現方式出現呢?我們可用看到在第一種實現方式中無法向單例模式的構造方法傳遞參數,而使用滯后初始化的方式,我們可用在調用getInstance()方法的時候向方法中傳遞參數。

          凡事有好處必然有壞處,滯后初始化的一個弊病就是在多線程或分布式的環(huán)境下有可能出現混亂:

              “有時在某些情況下,使用Singleton并不能達到Singleton的目的,如有多個Singleton對象同時被不同的類裝入器裝載;在EJB這樣的分布式系統中使用也要注意這種情況,因為EJB是跨服務器,跨JVM的。” --摘自www.jdon.com-《GoF 23種設計模式解析》

              “在多線程環(huán)境下,我們無法保證一個方法能夠持續(xù)運行到結束,其他線程的方法才開始運行。因而可能存在這樣一種情形:兩個線程幾乎同時嘗試初始化單例類。假設第一個方法發(fā)現單例為空,而第二個方法在此刻開始運行,它也會發(fā)現該單例為空。接下來,這兩個方法都將對該單例進行初始化。”  --摘自《Java設計模式》

              
          那么在多線程的環(huán)境下我們怎么更安全的使用單例模式呢?
            
            
              方式3:
             
           《Java并發(fā)編程》一書建議使用屬于當前類的鎖進行同步,代碼如下:

          public class Singleton 

              
          private static Singleton instance = null
          ;
             
          //注意這里的static非常重要,如果為對象變量則因為存在多份拷貝而起不到限制的作用

              private static Object classLock = Singleton.class
               
          public static Singleton getInstance() 
          {
                
          //這個方法比上面有所改進,不用每次都進行生成對象,只是第一次使用時生成實例

                    synchronized(classLock){
                        
          if (instance==null
          )
                    instance=
          new
           Singleton();
                        
          return
           instance;
                    }
           
                    }
                
               }



              在第一個線程開始滯后初始化的時候,如果有另一線程也準備開始初始化,這時候,第二個線程將停止執(zhí)行,等待獲取對象classLock的鎖。當第二個線程獲取這個鎖并開始執(zhí)行初始化的時候,它會發(fā)現該單例已不再為空(因為只存在該類的唯有實例,我們可以使用單個靜態(tài)鎖)。
             
           
              或者:

          public class Singleton
          {
             
          private Singleton() {}
            
             
          private static class
           SingletonHolder
             
          {
              
          private final static Singleton INSTANCE = new
           Singleton();
             }
            
             
          public static
           Singleton getInstance()
             
          {
              
          return
           SingletonHolder.INSTANCE;
             }

          }

              另一個解決辦法是在getInstance()方法聲明中添加synchronized關鍵字: 

          public static synchronized Singleton getInstance()

          5、使用注意事項
                  單例模式類不能實現Clonable接口,以防被克隆而產生多個實例
              
           public Object clone() throws 

          CloneNotSupportedException 
          {

                   
          throw new
           CloneNotSupportedException();

          }



                  單例模式類不能實現Serializable接口,以防被序列化而產生多個實例

                  根據不同的執(zhí)行,你的Singleton類和它的所有數據可能被當作垃圾收集。因此,在應用程序運行時,你必須保證存在一個Singleton類的實時引用。

                  

          posted on 2008-05-28 16:57 云淡風清 閱讀(750) 評論(0)  編輯  收藏 所屬分類: Design Patterns

          <2008年5月>
          27282930123
          45678910
          11121314151617
          18192021222324
          25262728293031
          1234567

          導航

          統計

          常用鏈接

          留言簿(1)

          隨筆分類(15)

          隨筆檔案(15)

          收藏夾(1)

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 库车县| 金湖县| 团风县| 牙克石市| 泗洪县| 大田县| 昌吉市| 乐陵市| 托里县| 宜城市| 吐鲁番市| 霍邱县| 古丈县| 林芝县| 积石山| 靖宇县| 石首市| 滨州市| 龙州县| 酉阳| 宁晋县| 沽源县| 凤城市| 巩留县| 石棉县| 织金县| 义马市| 临邑县| 灵丘县| 长治县| 封开县| 龙泉市| 聂荣县| 大冶市| 邢台县| 白山市| 东阿县| 扶绥县| 富民县| 喀什市| 棋牌|