回歸

          驀然回首,那人卻在燈火闌珊處

            BlogJava :: 首頁(yè) :: 聯(lián)系 :: 聚合  :: 管理
            4 Posts :: 2 Stories :: 12 Comments :: 0 Trackbacks
                現(xiàn)在大多數(shù)Java軟件工程師面試都會(huì)問(wèn)到這個(gè)問(wèn)題:什么是單例模式(Singleton),能否寫(xiě)出單例模式的示例代碼?單例模式是Gof中23個(gè)模式中最簡(jiǎn)單最容易入門的模式,學(xué)習(xí)它我們能更理性的感知模式的意義.

               [形成]

                Singleton Pattern 為什么會(huì)出現(xiàn)?在我們軟件開(kāi)發(fā)和架構(gòu)中,經(jīng)常遇到這樣的情形:我們需要一個(gè)類只能且僅能產(chǎn)生一個(gè)實(shí)例..比如表示一臺(tái)計(jì)算機(jī)的類,表示系統(tǒng)設(shè)定的類或者是表示窗口的類,還有為了節(jié)約資源,只讓產(chǎn)生一個(gè)實(shí)例..
               
                如何構(gòu)造這種情形?Singleton模式給我一個(gè)方案:


               [代碼示例]
                
                程序列表
             

          名稱

          說(shuō)明

          Singleton

          只有一個(gè)對(duì)象實(shí)例的類

          Main

          測(cè)試用的類



                [UML圖]
             
                

          [示例代碼和類的詮釋]

           1 package singleton;
           2 
           3 public class Singleton {
           4     private static Singleton singleton = new Singleton();
           5 
           6     private Singleton() {
           7         System.out.println("Create instance...");
           8     }
           9 
          10     public static Singleton getInstance() {
          11         return singleton;
          12     }
          13 }
          14 


                    Singleton  Class:
                      
                      1.該類只能產(chǎn)生一個(gè)對(duì)象實(shí)例

                      2.把該類的的singleton屬性設(shè)定為static再以Singleton;類的對(duì)象實(shí)例進(jìn)行初始化,這個(gè)初始化的過(guò)程僅加載Sington類的時(shí)候調(diào)用一次.(Line4) 

                      3.把Singleton 類的構(gòu)造函數(shù)限定為private,目的是為了防止從非Singleton類(其他類)調(diào)用構(gòu)造函數(shù)來(lái)產(chǎn)生實(shí)例,如果通過(guò)new方式來(lái)產(chǎn)生Singleton實(shí)例,會(huì)出現(xiàn)編譯錯(cuò)誤.這樣做是為了保險(xiǎn)己見(jiàn).(Line6) 

                      4.要得到Singleton實(shí)例的唯一方法就是調(diào)用類靜態(tài)方法getInstance().這個(gè)名字可以隨便取,只要方便理解就行.(Line 10) 

           1 package singleton;
           2 
           3 public class Main {
           4 
           5     public static void main(String[] args) {
           6         System.out.println("Start");
           7         Singleton obj1 = Singleton.getInstance();
           8         Singleton obj2 = Singleton.getInstance();
           9         if(obj1 == obj2){
          10             System.out.println("obj1和obj2是同一個(gè)對(duì)象實(shí)例");
          11         }else{
          12             System.out.println("obj1和obj2不是同一個(gè)對(duì)象實(shí)例");
          13         }
          14         System.out.println("End");
          15     }
          16 }
          17 


                 Main Class
                  1.該類是測(cè)試程序.
                  2.程序通過(guò)getInstance()方式產(chǎn)生兩個(gè)obj1和obj2實(shí)例.(Line 7,Line 8)
                  3.通過(guò)ojb1= =ojb2表達(dá)式來(lái)確定兩個(gè)對(duì)象是否相同,判定是否產(chǎn)生了Singleton的第二個(gè)示例.(Line9-12)
           

          示例程序的執(zhí)行結(jié)果
          Start
          Create instance...
          obj1和obj2是同一個(gè)對(duì)象實(shí)例
          End

                   執(zhí)行結(jié)果含義:
                          1. 的確如此,obj1和obj2是Singleton類的同一個(gè)且唯一的對(duì)象實(shí)例. 
                          2.當(dāng)程序執(zhí)行后,第一次調(diào)用getInstance的時(shí)候會(huì)初始化Singleton類,同時(shí)也會(huì)初始化static字段,也同時(shí)產(chǎn)生產(chǎn)生了一個(gè)唯一對(duì)象實(shí)例.




                [拓展思考]
             
          如下的另一一個(gè)單例模式的程序有什么隱患?

           1 package singleton;
           2 
           3 public class Singleton2 {
           4     
           5     private static Singleton2 singleton = null;
           6     
           7     private Singleton2(){
           8         System.out.println("已產(chǎn)生對(duì)象實(shí)例");
           9     }
          10     public static Singleton2 getInstance(){
          11         if(singleton == null){
          12             singleton = new Singleton2();
          13         }
          14         return singleton;
          15     }
          16 
          17 }
          18 

              [解答]
          當(dāng)多線程同時(shí)調(diào)用Singleton2.getInstance()方法時(shí),可能會(huì)產(chǎn)生多個(gè)對(duì)象實(shí)例,例如
          public class Main extends Thread{

              
          public static void main(String[] args) {
                  System.out.println(
          "Starts.");
                  
          new Main("A").start();
                  
          new Main("B").start();
                  
          new Main("C").start();
                  System.out.println(
          "End.");
              }

             
              
          public void run(){
                  Singleton2 obj 
          = Singleton2.getInstance();
                  System.out.println(getName()
          +": obj ="+obj);
              }

              
              
          public Main(String name){
                  
          super(name);
              }

          }




          public class Singleton2 {
              
          private static Singleton2 singleton2 = null;
              
          private Singleton2(){
                  System.out.println(
          "已產(chǎn)生對(duì)象實(shí)例");
                  solwDown();
              }


              
          public static Singleton2 getInstance(){
                  
          if(singleton2 == null){
                      singleton2 
          = new Singleton2();
                  }

                  
          return singleton2;
              }

              
               
          private  void solwDown(){
                   
          try{
                       Thread.sleep(
          1000);
                   }
          catch(InterruptedException e){
                       e.printStackTrace();
                   }

               }

          }


          執(zhí)行結(jié)果:

          Start.
          End.
          已產(chǎn)生對(duì)象實(shí)例.
          已產(chǎn)生對(duì)象實(shí)例.
          已產(chǎn)生對(duì)象實(shí)例.
          B: obj = Singleton2#2a9348
          C: obj = Singleton2#b91134
          A: obj = Singleton2#e343l12

          (#替換為@)

          之所以會(huì)知道這種情況是因?yàn)閕f(singleton = = null){ singleton = new Singleton2(); }判斷不夠嚴(yán)謹(jǐn)?shù)膶?dǎo)致。
          利用: singleton == null 判斷為空后去執(zhí)行new Singleton2()之前,可能會(huì)有其他線程來(lái)?yè)屜扰袛啾磉_(dá)式singleton == null,從而又執(zhí)行一遍創(chuàng)建實(shí)例的操作。

          解決辦法:
          給getInstance()方法添加Synchronized修飾符,即可修改成線程安全嚴(yán)謹(jǐn)?shù)膯卫J健?br />
          public class Singleton2 {
              
          private static Singleton2 singleton = null;

              
          private Singleton2() {
                  System.out.println(
          "已產(chǎn)生對(duì)象實(shí)例");
                  solwDown();
              }

              
          public static synchronized Singleton2 getInstance() {
                  
          if (singleton == null) {
                      singleton 
          = new Singleton2();
                  }
                  
          return singleton;
              }

              
          private void solwDown() {
                  
          try {
                      Thread.sleep(
          1000);
                  } 
          catch (InterruptedException e) {
                      e.printStackTrace();
                  }
              }
          }

          posted on 2007-06-08 11:36 回歸 閱讀(1222) 評(píng)論(7)  編輯  收藏 所屬分類: 個(gè)人原創(chuàng)

          Feedback

          # re: 親密接觸設(shè)計(jì)模式(二)-------Singleton(單例) 2007-06-08 12:57 dennis
          第一個(gè)示例少了static
          public static Singleton getInstance() {
          return singleton;
          }
          也沒(méi)有考慮多線程情況下的單例模式  回復(fù)  更多評(píng)論
            

          # re: 親密接觸設(shè)計(jì)模式(二)-------Singleton(單例) 2007-06-08 16:50 sitinspring
          多線程情況下的單例模式:

          1 public class Singleton{
          2 private static Singleton instance=null;
          3
          4 public static synchronized Singleton getInstance(){
          5 // 要用的時(shí)候再把Singleton建立起來(lái)
          6 if(instance==null){
          7 instance=new Singleton();
          8 }
          9
          10 return instance;
          11 }
          12 }


            回復(fù)  更多評(píng)論
            

          # re: 親密接觸設(shè)計(jì)模式(二)-------Singleton(單例) 2007-06-11 09:17 一點(diǎn)思想
          第一種實(shí)行的Singleton不存在多線程隱患,累以第一次加載時(shí)候就產(chǎn)生實(shí)例.你認(rèn)為呢?  回復(fù)  更多評(píng)論
            

          # re: 親密接觸設(shè)計(jì)模式(二)-------Singleton(單例) 2007-06-11 09:22 一點(diǎn)思想
          嗯,static寫(xiě)掉了,這是一個(gè)靜態(tài)方法,直接通過(guò)類名調(diào)用  回復(fù)  更多評(píng)論
            

          # re: 親密接觸設(shè)計(jì)模式(二)-------Singleton(單例) 2007-06-12 15:07 hardson
          synchronized 是多余的  回復(fù)  更多評(píng)論
            

          # re: 親密接觸設(shè)計(jì)模式(二)-------Singleton(單例) 2007-06-18 14:16 想飛就飛
          第二種方式需要synchronized 的吧  回復(fù)  更多評(píng)論
            

          # re: 親密接觸設(shè)計(jì)模式(二)-------Singleton(單例) 2011-03-09 21:03 回歸
          恩,寫(xiě)掉了,以后注意@一點(diǎn)思想
            回復(fù)  更多評(píng)論
            

          主站蜘蛛池模板: 黎川县| 竹山县| 龙海市| 玉树县| 沂水县| 刚察县| 石嘴山市| 威信县| 漾濞| 加查县| 茂名市| 新丰县| 乐陵市| 桃园县| 城固县| 绥宁县| 阜南县| 无极县| 江永县| 乡宁县| 万源市| 连江县| 独山县| 霍州市| 紫金县| 甘谷县| 保德县| 青州市| 华容县| 永清县| 明水县| 昭平县| 革吉县| 和田市| 凤翔县| 从化市| 慈利县| 杭州市| 临猗县| 陕西省| 沅陵县|