設計模式-單例模式(Singleton Pattern)

來源:互聯網
上載者:User

標籤:

本文由@呆代待殆原創,轉載請註明出處。

 

單例模式簡述

單例模式保證了我們的類只有一個執行個體,並且我們在任何時候都可以取得這個執行個體,其中保證我們的類有且僅有一個執行個體在某些時候是相當重要的事情,比如我們只需要一個線程池而不是兩個等等,但是我們也要注意,單例模式適用的情況比我們想象中的要少,所以請不要濫用這個模式。

 

單例模式具有的一些特徵

1,單例模式保證了我們的程式中有且僅有一個執行個體的存在。

2,我們在任何時候都能取得這個執行個體。

3,單例模式的構造方法是私人的,所以在不破壞這一私人條件的情況下單例類是不能作為父類存在的。

 

單例模式的定義與基本結構

單例模式只有一個類而已,所以實際上並不存在結構這一說= =,但是我們還是可以看一下它的定義。

定義:確保類有且僅有一個執行個體,並保證任何時候都能訪問這個執行個體。(這句話好像已經出現了好的次 = =)

 

單例模式的定義與結構都非常簡單,理解起來甚至不需要舉額外的例子,但是,真正去實現單例的時候我們還是有很多細節要注意的,那麼下面我們就在實際的代碼中繼續研究吧。

 

單例模式的代碼實現(Java版)

代碼實現

 1 public class MySingleten { 2     public static MySingleten instance=null;//指向執行個體的變數 3     private MySingleten(){}//私人化建構函式,然別的代碼無法建立這個類的執行個體 4     public static MySingleten getInstance(){//我們取得這個單例的方法。 5         if(null==instance){ 6             instance=new MySingleten(); 7         } 8         return instance; 9     }10     public void MyFunction(){//一般方法的代表11         System.out.println("我是單例,這是我的方法");12     }13 }

這種實現方式我們一般叫它:懶漢式

為什麼呢?因為它直到第一次被調用的時候才會產生自己的執行個體(就像我們每次都要到交作業的時候才會開始寫作業一樣,總之就是懶唄= ̄ω ̄=)

 

注意:懶漢式是線程不安全的

舉例:想象一下情況,線程A執行到代碼的第5行,判斷成功,在準備進入第6行的時候CPU切換了,線程B恰好也執行這段代碼,這時很明顯instance還是==null的浴室線程B成功建立了一個instance的執行個體,結果,當CPU又切回線程A時,麻煩來了,線程A繼續執行第6行代碼又建立了一個instance的執行個體,並把原來的那個覆蓋了,這就很有可能導致意想不到的問題。

 

所以,我們必須想辦法解決這個問題,這裡我們提供以下幾種思路。

餓漢式:不再等到要使用的時候才建立,而是在程式開始的時候就建立好(對這個執行個體很饑渴的樣子,所以叫餓(chi)漢式)

 1 public class MySingleten { 2     public static MySingleten instance=new MySingleten();//一開始就產生這個變數就不存線上程問題了 3     private MySingleten(){} 4     public static MySingleten getInstance(){ 5         return instance; 6     } 7     public void MyFunction(){ 8         System.out.println("我是單例,這是我的方法"); 9     }10 }

 

synchronized方法:直接在懶漢式的getInstance方法前加上synchronized修飾符,這樣就能解決安全執行緒問題了,這個解決方案是最簡單的,但是效率卻非常低下,因為只有第一次建立執行個體的時候這個synchronized是有必要的,當執行個體建立完成後,這個synchronized就只剩下拖慢速度的作用了。

 1 public class MySingleten { 2     public static MySingleten instance=null; 3     private MySingleten(){} 4     public static synchronized  MySingleten getInstance(){ 5         if(null==instance){ 6             instance=new MySingleten(); 7         } 8         return instance; 9     }10     public void MyFunction(){11         System.out.println("我是單例,這是我的方法");12     }13 }

 

雙重加鎖方法:在懶漢式的基礎上,我們可以用兩把鎖來分別控制單例的取得和建立,因為只需要在第一次建立單例的時候注意安全執行緒問題,那麼,我們在內層鎖上用synchronized來控制,在外層鎖上用 if(null==instance) 來判斷是否存在這個執行個體,這樣就省去了synchronized在後來浪費的同步時間

 1 public class MySingleten { 2     public volatile static MySingleten instance=null;//注意這裡增加了volatile關鍵字 3     private MySingleten() {} 4     public static MySingleten getInstance() { 5         if (null == instance) {// 外層鎖,判斷是否執行個體已經被建立 6             synchronized (MySingleten.class) {// 內層鎖控制線程間同步,執行個體被建立後就沒有啟動並執行機會了,省去了多餘的線程間同步成本 7                 if(null==instance)//需要再次檢查,因為很有可能線程A在這裡時,線程B已經通過外層的if了。 8                     instance = new MySingleten(); 9             }10         }11         return instance;12     }13     public void MyFunction() {14         System.out.println("我是單例,這是我的方法");15     }16 }

 

靜態全域變數和單例模式的對比

1,靜態全域變數並不能保證對象是唯一的(既然你能建立這個靜態全域變數就說明這個類的建構函式並不是私人的)。

2,多餘的全域變數會造成命名空間的汙染。

3,全域變數總是存在,會一直佔用記憶體,而單例模式可實現訪問的時候再建立單例的執行個體。

4,單例模式產生的對象儲存在堆裡,但是靜態全域變數儲存在棧裡。

 

靜態成員和單例模式的對比

1,用都是靜態成員的類去類比單例的話,它是不能實現別的介面的,這種用法脫離了物件導向的思想(除非這個類的應用與實現不需要物件導向的思想那麼你可以這麼做)。

2,靜態成員可以選擇性的將類裡面的東西分成需要保證唯一性的和不需要保證唯一性的,某些時候更加靈活。

 

java版本相容性提醒

1,Java1.2之前的記憶體回收機制是有bug的,會造成當單例執行個體在沒有全域引用的情況下被清除掉。

2,Java1.4之前許多JVM對於volatile的實現會導致雙重加鎖的方法失效

 

關於單例模式的一些爭議

如果你剛剛看完了我寫的博文並覺得又有了一點收穫而感到很開心的話(如果真的是這樣那我也會很開心的?(^∇^*)),我覺得你可以先冷靜一下(大霧= =),單例設計模式在網路上是一個很有爭議的模式,有人覺得這個模式違反了太多的設計原則,有人覺他增加了代碼的耦合性等等,但有的時候我們又確實需要單例帶給我們的一些特性,本來博主想多看一些別人的文章後幫大家總結一下網路上關於這方面的討論,結果博主發現這些討論實在是太多了,而且比較雜,各種聲音都有,stackoverflow上有個類似的問題以"這個問題的回答是基於個人選擇而不是基於經驗的..."而被關閉了,所以博主覺得還是選一些博主覺得比較好的串連給各位,讓各位自行斟酌比較好。(相關討論的串連都放在了參考資料裡,如果覺得不夠的話,可以直接google一下"singleton why bad")

 

 

參考資料:

1,《Head First 設計模式》

2,https://agiletribe.wordpress.com/2013/10/08/dont-abuse-singleton-pattern/ 關於何時才應該使用單例模式

3,https://www.cnblogs.com/seesea125/archive/2012/04/05/2433463.html關於為什麼不用靜態方法而要用單例模式

4,https://stackoverflow.com/questions/137975/what-is-so-bad-about-singletons關於單例模式爭議的討論

5,https://stackoverflow.com/questions/519520/difference-between-static-class-and-singleton-pattern關於單例模式和靜態類之間的討論

設計模式-單例模式(Singleton Pattern)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.