beauty_beast

          上善若水 厚德載物

          學習設計模式之singleton模式

          Posted on 2005-08-18 21:09 柳隨風 閱讀(539) 評論(1)  編輯  收藏
          本文只是本人的學習總結,目的希望能和大家一起交流分享,順便備忘,如有不正確的地方,歡迎指正。

          singleton模式我們在開發時經常會使用到,比如將一個系統運行時的初始配置數據封裝成一個配置對象,在系統初始化時實例化該對象,因為對于整個系統運行時該對象的成員都是不變的,如果只需要一個實例就行,這樣對系統的性能是很有益的。往往該配置對象都是和資源密切相關的(例如 數據庫連接、文件等等),但是如果采用該模式設計、編碼不當,常會造成資源泄漏,甚至更嚴重的問題(我的最近一個項目就出現過問題)。
          一個簡單的單實例模式實現如下:
          /*
           * Created on 2005-8-18
           *
           * TODO To change the template for this generated file go to
           * Window - Preferences - Java - Code Style - Code Templates
           
          */

          package study.design.singleton;



          /**
           * @author liusuifeng
           * 
           * TODO To change the template for this generated type comment go to Window -
           * Preferences - Java - Code Style - Code Templates
           
          */

          public class TestSingleTon   {
              
          private static TestSingleTon test = null;

              
          private TestSingleTon() {

                  System.
          out.println("contructor has been inited");
              }


              
          public static synchronized TestSingleTon getInstance() {
                  
          if (test == null{

                      test 
          = new TestSingleTon();

                  }

                  
          return test;
              }


          }


          這樣的定義在單線程應用中時沒有問題的,但是如果是多線程訪問的話實際就不是單實例了:
          舉個簡單例子:

          /*
           * Created on 2005-8-18
           *
           * TODO To change the template for this generated file go to
           * Window - Preferences - Java - Code Style - Code Templates
           
          */
          package study.design.singleton;

          /**
           * @author liusuifeng
           
           
          */
          public class TestThread extends Thread {
              
          public void run(){
                  TestSingleTon test
          =TestSingleTon.getInstance();        
                  System.
          out.println("TestSingleTon===="+test);
                  
              }
              
              
          public static void main(String[] args){
                  
          for(int i=0;i<10;i++){
                      TestThread mthread
          =new TestThread();                
                      mthread.start();
                  }        
              }
              
              
          }


          運行時系統輸出如下:
          TestSingleTon====study.design.singleton.TestSingleTon@107077e
          TestSingleTon====study.design.singleton.TestSingleTon@7ced01
          TestSingleTon====study.design.singleton.TestSingleTon@1ac04e8
          TestSingleTon====study.design.singleton.TestSingleTon@1ac04e8
          TestSingleTon====study.design.singleton.TestSingleTon@1ac04e8
          TestSingleTon====study.design.singleton.TestSingleTon@1ac04e8
          TestSingleTon====study.design.singleton.TestSingleTon@1ac04e8
          TestSingleTon====study.design.singleton.TestSingleTon@1ac04e8
          TestSingleTon====study.design.singleton.TestSingleTon@1ac04e8

          呵呵,單實例變成三實例了,所以我們編碼、設計時一定要考慮該對象的調用環境,保險起見,我們可以加上同步,修改原來的實現,將方法加上同步:
          public static synchronized TestSingleTon getInstance() {
                  
          if (test == null{

                      test 
          = new TestSingleTon();

                  }

                  
          return test;
              }

          執行測試代碼輸出:
          TestSingleTon====study.design.singleton.TestSingleTon@11a698a
          TestSingleTon====study.design.singleton.TestSingleTon@11a698a
          TestSingleTon====study.design.singleton.TestSingleTon@11a698a
          TestSingleTon====study.design.singleton.TestSingleTon@11a698a
          TestSingleTon====study.design.singleton.TestSingleTon@11a698a
          TestSingleTon====study.design.singleton.TestSingleTon@11a698a
          TestSingleTon====study.design.singleton.TestSingleTon@11a698a
          TestSingleTon====study.design.singleton.TestSingleTon@11a698a
          TestSingleTon====study.design.singleton.TestSingleTon@11a698a

          這樣就保證了多線程調用時也只有一個實例。
          呵呵,這樣就能保證在同一虛擬機上只有一個實例了嗎?
          如果對象是個可序列化的對象呢?
          /*
           * Created on 2005-8-18
           *
           * TODO To change the template for this generated file go to
           * Window - Preferences - Java - Code Style - Code Templates
           
          */
          package study.design.singleton;


          import java.io.Serializable;

          /**
           * @author liusuifeng
           * 
           * TODO To change the template for this generated type comment go to Window -
           * Preferences - Java - Code Style - Code Templates
           
          */
          public class TestSingleTon implements Serializable {
              
          private static TestSingleTon test = null;

              
          private TestSingleTon() {

                  System.
          out.println("contructor has been inited");
              }

              
          public static synchronized TestSingleTon getInstance() {
                  
          if (test == null) {

                      test 
          = new TestSingleTon();

                  }
                  
          return test;
              }

          }

          下面的方法就又偷出一個實例出來:
          /*
           * Created on 2005-8-18
           *
           * TODO To change the template for this generated file go to
           * Window - Preferences - Java - Code Style - Code Templates
           
          */
          package study.design.singleton;

          import java.io.FileInputStream;
          import java.io.FileNotFoundException;
          import java.io.FileOutputStream;
          import java.io.IOException;
          import java.io.ObjectInputStream;
          import java.io.ObjectOutputStream;

          /**
           * @author liusuifeng
           * 
           * TODO To change the template for this generated type comment go to Window -
           * Preferences - Java - Code Style - Code Templates
           
          */
          public class TestSerialObject {
              
              
          private void writeObject() {
                  TestSingleTon tempobj 
          = TestSingleTon.getInstance();
                  ObjectOutputStream oos
          =null;
                  
          try {
                      oos 
          = new ObjectOutputStream(
                              
          new FileOutputStream("c:\\object.data"));
                      oos.writeObject(tempobj);
                  } 
          catch (FileNotFoundException e1) {
                      
                      e1.printStackTrace();
                  } 
          catch (IOException e1) {            
                      e1.printStackTrace();
                  }
                  
          finally{
                      
          try {
                          oos.close();
                      } 
          catch (IOException e) {
                          
                          e.printStackTrace();
                      }
                  }

              }

              
          public Object getSerialObject() {
                  Object o 
          = new Object();
                  ObjectInputStream ois 
          =null;
                  writeObject();
                  
          try {
                       ois 
          = new ObjectInputStream(new FileInputStream(
                              
          "c:\\object.data"));
                       o
          =ois.readObject();
                      
                  } 
          catch (FileNotFoundException e) {            
                      e.printStackTrace();
                  } 
          catch (IOException e) {
                      
                      e.printStackTrace();
                  } 
          catch (ClassNotFoundException e) {
                      
                      e.printStackTrace();
                  }
                  
          finally{
                      
          try {
                          ois.close();
                      } 
          catch (IOException e1) {
                          e1.printStackTrace();
                      }
                  }
                  
          return o;
              }

              
          public static void main(String[] args) {
                  TestSerialObject to
          =new TestSerialObject();            
                  Object obj1
          =to.getSerialObject();
                  System.
          out.println(obj1.equals(TestSingleTon.getInstance()));
              }
          }

          運行輸出如下:
          contructor has been inited
          false

          學習總結如下:
              采用單實例模式時設計編碼時要盡可能的多考慮其調用場景,在實現中規避不應該出現的多實例情形。














          Feedback

          # re: 學習設計模式之singleton模式  回復  更多評論   

          2005-08-18 22:03 by Rocky
          呵呵,我再補充一點,關于單實例。

          版主例子中給了單實例的一種實現:
          public class TestClass
          {
          private static TestClass instance;
          private TestClass(){}

          public static TestClass()
          {
          if( null != instance) instance = new TestClass();
          return instance;
          }
          public void testA(){};
          public void testB(){};
          }

          這種是比較常用的,但有這么一個問題。即該類一旦實例化,那么將永遠不能被回收。即使你將 instance 賦成 null,也不能將該類清除掉。


          還有一種單實例模式,見下:
          public class TestClass
          {
          private String aaa;
          public TestClass(){
          //初始化單實例中的一些變量
          aaa = .....;
          }

          public static void testA(){
          //針對aaa的操作
          }

          public static void testB(){}{
          //針對aaa的操作
          }
          }
          即將方法聲明為 static 方法。這樣聲明之后,那么針對aaa的操作的所有行為也將遵循單實例模式。

          這種方式的優點就是類的實例可以隨時銷毀。但有個缺點:即每次調用都需要創建一個實例出來,有時間上的開銷。

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


          網站導航:
           
          主站蜘蛛池模板: 南充市| 漠河县| 新蔡县| 杨浦区| 高安市| 涡阳县| 达州市| 辉南县| 顺平县| 灵宝市| 天台县| 六枝特区| 新乡市| 新乐市| 宁安市| 新沂市| 类乌齐县| 林口县| 读书| 凭祥市| 邵武市| 离岛区| 泗阳县| 来凤县| 自贡市| 万州区| 绥阳县| 阆中市| 安图县| 沛县| 泰州市| 平邑县| 洮南市| 邵东县| 哈尔滨市| 宁河县| 溆浦县| 湘西| 仪征市| 新干县| 洛隆县|