單例模式之怎么實現(xiàn)我的機(jī)器人女友

本篇內(nèi)容介紹了“單例模式之怎么實現(xiàn)我的機(jī)器人女友”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

成都創(chuàng)新互聯(lián)公司專注于浦城企業(yè)網(wǎng)站建設(shè),響應(yīng)式網(wǎng)站建設(shè),成都做商城網(wǎng)站。浦城網(wǎng)站建設(shè)公司,為浦城等地區(qū)提供建站服務(wù)。全流程按需求定制制作,專業(yè)設(shè)計,全程項目跟蹤,成都創(chuàng)新互聯(lián)公司專業(yè)和態(tài)度為您提供的服務(wù)

程序代碼如下:


   
   
  
public class GirlFriend {

   private String name;

   public GirlFriend(String name) {
       this.name = name;
       System.out.println("機(jī)器人女友制作完成");
   }

   public void smile() {
       System.out.println("笑一個 :-)");
   }

   public void housework() {
       System.out.println("去干家務(wù)");
   }

   public void buKeMiaoShu() {
       System.out.println(".......");
   }
}
     
操作也很簡單,直接創(chuàng)建對象就行了。

   
   
  
public static void main(String[] args) {
    GirlFriend girlFriend = new GirlFriend("小麗");
    girlFriend.smile();
    girlFriend.housework();
    girlFriend.buKeMiaoShu();
}
     
你看,馬上就能干活了。

   
   
  
機(jī)器人女友制作完成
笑一個 :-)
去干家務(wù)
.......
     
小帥很快發(fā)現(xiàn)了一個漏洞,如果材料足夠,他能創(chuàng)造無數(shù)個對象。
很快,小帥就在黑市上購買了一套材料,回家啟動機(jī)器,果然制造出了第二個機(jī)器人女友。
小帥難掩心中的興奮,盤算著,再去黑市買幾套材料回來,不就能打印很多個“女友”了?

單例模式


創(chuàng)新基因公司的監(jiān)控系統(tǒng)很快就發(fā)現(xiàn)了這個問題,工程師們加班加點在線升級了系統(tǒng)。
他們采用了一種叫做單例模式的設(shè)計模式來保證一臺機(jī)器只能生成一個對象。

單例模式之怎么實現(xiàn)我的機(jī)器人女友


 更新后的代碼如下:

   
   
  
public class GirlFriend {

   private static GirlFriend girlFriend;

   private String name;

   private GirlFriend(String name) {
       this.name = name;
       System.out.println("機(jī)器人女友制作完成");
   }

   /**
    * 對象通過getInstance方法獲取
    * @param name
    * @return
    */
   public static GirlFriend getInstance(String name) {
       if(girlFriend == null) {
           girlFriend = new GirlFriend(name);
       }
       return girlFriend;
   }

   public void smile() {
       System.out.println("笑一個 :-)");
   }

   public void housework() {
       System.out.println("去干家務(wù)");
   }

   public void buKeMiaoShu() {
       System.out.println(".......");
   }
}
     

   
   
  
public static void main(String[] args) {
   GirlFriend girlFriend = GirlFriend.getInstance("小麗");
   girlFriend.smile();
   girlFriend.housework();
   girlFriend.buKeMiaoShu();
}
     
創(chuàng)新基因公司的工程師們很滿意,他們開了一個盛大的party,慶祝工作的圓滿完成。
小帥花了重金,在黑市上買了好幾套材料,打算回家打造一個“后宮團(tuán)”,想想以后的日子真是美滋滋啊。
小帥打開程序一看傻了眼,運行了好多次,獲取的都是同一個對象,“后宮”夢就此破裂了嗎?
小帥不甘心啊。
經(jīng)過幾天苦思冥想,小帥終于想到了破解方法,這就是多線程:

   
   
  
public static void main(String[] args){
   for(int i = 0; i < 5; i++) {
       new Thread(new Runnable() {
           @Override
           public void run() {
               GirlFriend girlFriend = GirlFriend.getInstance("小麗");
               System.out.println(girlFriend);
           }
       }).start();
   }
}
     
5個線程同時運行,順利創(chuàng)建了3個不同的對象。

   
   
  
機(jī)器人女友制作完成
singleton.singleton.GirlFriend@95458f7
機(jī)器人女友制作完成
機(jī)器人女友制作完成
singleton.singleton.GirlFriend@d9d8ad0
singleton.singleton.GirlFriend@383a0ba
singleton.singleton.GirlFriend@d9d8ad0
singleton.singleton.GirlFriend@d9d8ad0
     
“嗚。嗚。嗚?!?,創(chuàng)新基因公司的報警器又響了起來,工程師們都一臉懵逼,這么完美的單例模式怎么還有破綻呢?
最后還是技術(shù)總監(jiān)親自出馬,給工程師們講解,順便畫了一幅圖:

單例模式之怎么實現(xiàn)我的機(jī)器人女友


 線程1和線程2判斷girlFriend的時候如果都為空,就會各自創(chuàng)建一個對象,最后就會返回兩個不同的對象了。

工程師們恍然大悟。
“誰知道如何改進(jìn)嗎?”技術(shù)總監(jiān)問道。

懶漢式

“這個簡單,在getInstance方法上加個synchronized關(guān)鍵字就行了!”程序員老王得意的說。

   
   
  
/**
* 對象通過getInstance方法獲取
 * @param name
 * @return
 */
public synchronized static GirlFriend getInstance(String name) {
    if(girlFriend == null) {
        girlFriend = new GirlFriend(name);
    }
    return girlFriend;
}
     
“這樣確實可以,不過,”技術(shù)總監(jiān)話鋒一轉(zhuǎn),“你有沒有考慮過效率問題?”
“synchronized同步方法只有第一次創(chuàng)建對象的時候能用到,也就是說一旦創(chuàng)建了girlFriend對象后就用不到這個同步功能了,但是以后每次調(diào)用getInstance方法都會進(jìn)入同步代碼,嚴(yán)重降低了效率?!?/section>
技術(shù)總監(jiān)犀利地指出了問題所在。

餓漢式

“還有個辦法,可以用全局變量,在類加載的時候就創(chuàng)建對象,所以,實例的創(chuàng)建過程是線程安全的?!背绦騿T小李也想出了一個辦法。

   
   
  
public class GirlFriend {

   // 在類加載的時候就創(chuàng)建對象,是線程安全的
   private static GirlFriend girlFriend = new GirlFriend("小麗");

   private String name;

   private GirlFriend(String name) {
       this.name = name;
       System.out.println("機(jī)器人女友制作完成");
   }

   /**
    * 對象通過getInstance方法獲取
    * @return
    */
   public static GirlFriend getInstance() {
       return girlFriend;
   }

   public void smile() {
       System.out.println("笑一個 :-)");
   }

   public void housework() {
       System.out.println("去干家務(wù)");
   }

   public void buKeMiaoShu() {
       System.out.println(".......");
   }
}
     
技術(shù)總監(jiān)說:“這是個辦法,不過,這樣的實現(xiàn)方式有幾個問題需要考慮。”
  • 不支持延遲加載(在真正用到對象的時候,再創(chuàng)建實例),在類加載的時候?qū)ο缶蛣?chuàng)建好了,如果對象在整個程序中一次都用不到,提前創(chuàng)建就浪費了。

  • 不能控制對象的數(shù)量,我們完全可以聲明多個對象,比如:GirlFriend girlFriend1;GirlFriend girlFriend2;GirlFriend girlFriend3。

  • 我們可能沒有足夠的信息在靜態(tài)初始化時,實例化每一個對象,對象的構(gòu)造方法參數(shù),可能要依賴程序后面的運算結(jié)果。


但是,我們要活學(xué)活用,如果創(chuàng)建對象比較耗時,等我們用到的時候再創(chuàng)建就會很慢,我們想在程序加載的時候提前創(chuàng)建好,是可以用這種方式的。  
“還有沒有其他方法?”技術(shù)總監(jiān)追問道。

雙重檢測

“還有一種辦法,把同步鎖放到方法里面,雙重檢測?!背绦騿T老王想了好久,終于想出了另一種方法。

   
   
  
public class GirlFriend {

   // volatile關(guān)鍵字保證了每個線程看到的girlFriend對象都是最新的
   private volatile static GirlFriend girlFriend;

   private String name;

   private GirlFriend(String name) {
       this.name = name;
       System.out.println("機(jī)器人女友制作完成");
   }

   /**
    * 對象通過getInstance方法獲取
    * @param name
    * @return
    */
   public static GirlFriend getInstance(String name) {
       if(girlFriend == null) {
           synchronized (GirlFriend.class) {
               if (girlFriend == null) {
                   girlFriend = new GirlFriend(name);
               }
           }
       }
       return girlFriend;
   }

   public void smile() {
       System.out.println("笑一個 :-)");
   }

   public void housework() {
       System.out.println("去干家務(wù)");
   }

   public void buKeMiaoShu() {
       System.out.println(".......");
   }
}
     
“檢查girlFriend對象的時候,如果為null就進(jìn)入同步代碼,每個線程重新判斷girlFriend對象是否為空,volatile關(guān)鍵字保證了每個線程看到的girlFriend對象都是最新的(在高版本的 Java中,這里已經(jīng)不需要使用volatile了)。”
“如果girlFriend對象已經(jīng)創(chuàng)建了,以后就不會進(jìn)入同步代碼了,這樣就保證了效率?!崩贤踅忉尩馈?/section>
“恩,這是個好方法,這樣就解決懶漢式方法的低性能和餓漢式方法的延遲加載問題,我們就采用這個方案升級代碼吧?!奔夹g(shù)總監(jiān)贊許道。

總結(jié)

單例模式(Singleton Pattern):單例模式確保一個類僅有一個實例,并提供一個訪問它的全局訪問點。
單例模式的有三個要點:
  • 某個類只能有一個實例

  • 它必須自行創(chuàng)建這個實例

  • 它必須自行向整個系統(tǒng)提供這個實例

單例模式是一種對象創(chuàng)建型模式。
單例模式又名單件模式或單態(tài)模式。
單例的實現(xiàn)單例有下面幾種經(jīng)典的實現(xiàn)方式:
- 懶漢式
懶漢式相對于餓漢式的優(yōu)勢是支持延遲加載。但是,這種實現(xiàn)方式會導(dǎo)致頻繁加鎖、釋放鎖,以及并發(fā)度低等問題,頻繁的調(diào)用會產(chǎn)生性能瓶頸。
- 餓漢式
餓漢式的實現(xiàn)方式,在類加載的期間,就已經(jīng)將靜態(tài)實例初始化好了,所以,實例的創(chuàng)建是線程安全的。不過,這樣的實現(xiàn)方式不支持延遲加載實例。
- 雙重檢測
雙重檢測的實現(xiàn)方式是既支持延遲加載、又支持高并發(fā)的單例實現(xiàn)方式。只要實例被創(chuàng)建之后,再調(diào)用 getInstance() 函數(shù)都不會進(jìn)入到加鎖邏輯中。

“單例模式之怎么實現(xiàn)我的機(jī)器人女友”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!

網(wǎng)頁標(biāo)題:單例模式之怎么實現(xiàn)我的機(jī)器人女友
轉(zhuǎn)載來于:http://bm7419.com/article14/ijhoge.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站制作手機(jī)網(wǎng)站建設(shè)、軟件開發(fā)、品牌網(wǎng)站制作網(wǎng)站維護(hù)、動態(tài)網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

網(wǎng)站建設(shè)網(wǎng)站維護(hù)公司