資源描述:
《設計模式-單例模式》由會員上傳分享,免費在線閱讀,更多相關內容在工程資料-天天文庫。
1、設計模式-單例模式為什么需要單例模式有時候我們需要使用一個實用類A,這個類A專門提供一些公共功能供別人調用,而本身并不會處理業(yè)務邏輯。由于類A會被許多類乃至線程調用,假設我們的程序非常龐大,在運行的過程中,會訪問這個類A100次,為了調用類A的方法,需要先創(chuàng)建A的對象,Aa=newA()。這種方法在對A的訪問量較少的情況下沒問題,但是像我們這種情況,就會創(chuàng)建100個類A的實例,這100個實例是要占用內存的,從這種角度來說,就造成了大量不必要的開銷。而單例模式,在整個程序生命周期中,只有一個實例,這樣就不
2、會造成不必要的內存消耗。單例模式的設計為了讓整個生命周期內只有一個實例,我們可以這樣做:publicclassSingleton{privatestaticSingletonsSingleton;privateSingleton(){}publicstaticSingletongetInstance(){if(sSingleton==null){sSingleton=newSingleton();//lineA}returnsSingleton;}}上述做法好像沒啥問題,由于mSingleton是靜態(tài)的
3、,因此能夠保證程序運行過程中只存在一個實例。但是針對多線程情況,就可能有問題,比如有2個線程同時并發(fā)調用getInstance方法,并且同時執(zhí)行到了lineA,這個時候還是會各自new一個對象出來,也就是說,存在了兩個實例,這違背了單例模式的概念,下面我們改進一下:publicclassSingleton{privatestaticSingletonsSingleton;privateSingleton(){}publicstaticSingletongetInstance(){synchronized
4、(Singleton.class){if(mSingleton==null){sSingleton=newSingleton();}returnsSingleton;}}}上述做法的確是沒啥問題了,getInstance方法中對Singleton.class加鎖,可以保證同一時刻只有一個線程能夠進入getInstance方法?,F在考慮一種情況,還是我們的比較龐大的工程,在某個變態(tài)的時刻,我們需要訪問Singleton對象100次,注意是高并發(fā)下的同時訪問,會是什么情形呢?大概是這樣的:100個線程進入g
5、etInstance方法以后開始搶mSingleton的所有權,這個時候,有一個線程獲得了鎖,然后順利地得到了Singleton實例,接著會是什么情形呢?應該是這樣的:剩下99個線程開始搶mSingleton的所有權,一直這樣類推下去,可能有一個線程運氣比較差,搶了100次才搶到鎖,程序的表現可能是這樣的:這個運氣差的線程被阻塞在getInstance方法中,遲遲無法返回,如果需要返回數據給ui的話,那么ui將遲遲不會得到更新。我們需要看一下上述代碼,真的需要每次進入getInstance方法都要獲得鎖
6、嗎?其實不是的,整個Singleton類中,對mSingleton進行訪問的地方分為兩類:讀和寫,而且僅當mSingleton為null的時候才會寫,mSingleton一旦創(chuàng)建完畢,后面就只剩下讀操作了,再怎么高并發(fā)也沒什么關系了,反正mSingleton已經是現成的,直接讀就可以了,看如下采用double-check機制的改進代碼:publicclassSingleton{privatevolatilestaticSingletonsSingleton;privateSingleton(){}pub
7、licstaticSingletongetInstance(){if(sSingleton==null){//lineAsynchronized(Singleton.class){//lineCif(sSingleton==null)sSingleton=newSingleton();//lineB}}returnsSingleton;}}上述代碼近乎完美,可以滿足幾乎所有場合(采用反射和類加載器另當別論)。上述代碼的好處在于:第一次創(chuàng)建實例的時候會同步所有線程,以后有線程再想獲取Singleton的實
8、例就不需要進行同步,直接返回實例即可。還有double-check的意義在于:假設現在有2個線程A和B同時進入了getInstance方法,線程A執(zhí)行到lineA行,線程B執(zhí)行到lineB行,由于B線程還沒有初始化完畢,sSingleton還是null,于是線程A通過了sSingleton==null的判斷,并且往下執(zhí)行,碰巧,當線程A執(zhí)行到lineC的時候,線程B初始化完畢了,然后線程B返回,注意,如果沒有double-check,這個時