單例模式(單例設(shè)計(jì)模式)_第1頁(yè)
單例模式(單例設(shè)計(jì)模式)_第2頁(yè)
單例模式(單例設(shè)計(jì)模式)_第3頁(yè)
單例模式(單例設(shè)計(jì)模式)_第4頁(yè)
單例模式(單例設(shè)計(jì)模式)_第5頁(yè)
已閱讀5頁(yè),還剩6頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、單例模式(單例設(shè)計(jì)模式)在有些系統(tǒng)中,為了節(jié)省內(nèi)存資源、保證數(shù)據(jù)內(nèi)容的一致性,對(duì)某些類要求只能創(chuàng)建一個(gè)實(shí)例,這就是所謂的單例模式。單例模式的定義與特點(diǎn)單例(Singleton)模式的定義:指一個(gè)類只有一個(gè)實(shí)例,且該類能自行創(chuàng)建這個(gè)實(shí)例的一種模式。例如,Windows中只能打開管理器,這樣可以避免因打開多個(gè)任務(wù)管理器窗口而造成內(nèi)存資源的浪費(fèi),或出現(xiàn)各個(gè)窗口顯示內(nèi)容的不一致等錯(cuò)誤。在計(jì)算機(jī)系統(tǒng)中,還有Windows的回收站、操作系統(tǒng)中的文件系統(tǒng)、多線程中的線程池、顯卡的驅(qū)動(dòng)程序?qū)ο?、打印機(jī)的后臺(tái)處理服務(wù)、應(yīng)用程序的日志對(duì)象、數(shù)據(jù)庫(kù)的連接池、網(wǎng)站的計(jì)數(shù)器、Web應(yīng)用的配置對(duì)象、應(yīng)用程序中的對(duì)話框、系

2、統(tǒng)中的緩存等常常被設(shè)計(jì)成單例。單例模式在現(xiàn)實(shí)生活中的應(yīng)用也非常廣泛,例如公司CEO、部門經(jīng)理等都屬于單例模型。J2EE標(biāo)準(zhǔn)中的Context和ServletContextConfig、框架應(yīng)用中的ApplicationContext、數(shù)據(jù)庫(kù)中的連接池等也都是單例模式。單例模式有3個(gè)特點(diǎn):?jiǎn)卫愔挥幸粋€(gè)實(shí)例對(duì)象;該單例對(duì)象必須由單例類自行創(chuàng)建;單例類對(duì)外提供一個(gè)訪問該單例的全局訪問點(diǎn)。單例模式的優(yōu)點(diǎn)和缺點(diǎn)單例模式的優(yōu)點(diǎn):?jiǎn)卫J娇梢员WC內(nèi)存里只有一個(gè)實(shí)例,減少了內(nèi)存的開銷。可以避免對(duì)資源的多重占用。單例模式設(shè)置全局訪問點(diǎn),可以優(yōu)化和共享資源的訪問。單例模式的缺點(diǎn):?jiǎn)卫J揭话銢]有接口,擴(kuò)展困難。

3、如果要擴(kuò)展,則除了修改原來的代碼,沒有第二種途徑,違背開閉原則。在并發(fā)測(cè)試中,單例模式不利于代碼調(diào)試。在調(diào)試過程中,如果單例中的代碼沒有執(zhí)行完,也不能模擬生成一個(gè)新的對(duì)象。單例模式的功能代碼通常寫在一個(gè)類中,如果功能設(shè)計(jì)不合理,則很容易違背單一職責(zé)原則。單例模式看起來非常簡(jiǎn)單,實(shí)現(xiàn)起來也非常簡(jiǎn)單。單例模式在面試中是一個(gè)高頻面試題。希望大家能夠認(rèn)真學(xué)習(xí),掌握單例模式,提升核心競(jìng)爭(zhēng)力,給面試加分,順利拿到Offer。單例模式的應(yīng)用場(chǎng)景對(duì)于來說,單例模式可以保證在一個(gè)JVM中只存在單一實(shí)例。單例模式的應(yīng)用場(chǎng)景主要有以下幾個(gè)方面。需要頻繁創(chuàng)建的一些類,使用單例可以降低系統(tǒng)的內(nèi)存壓力,減少GC。某類只要

4、求生成一個(gè)對(duì)象的時(shí)候,如一個(gè)班中的班長(zhǎng)、每個(gè)人的身份證號(hào)等。某些類創(chuàng)建實(shí)例時(shí)占用資源較多,或?qū)嵗臅r(shí)較長(zhǎng),且經(jīng)常使用。某類需要頻繁實(shí)例化,而創(chuàng)建的對(duì)象又頻繁被銷毀的時(shí)候,如多線程的線程池、網(wǎng)絡(luò)連接池等。頻繁訪問數(shù)據(jù)庫(kù)或文件的對(duì)象。對(duì)于一些控制硬件級(jí)別的操作,或者從系統(tǒng)上來講應(yīng)當(dāng)是單一控制邏輯的操作,如果有多個(gè)實(shí)例,則系統(tǒng)會(huì)完全亂套。當(dāng)對(duì)象需要被共享的場(chǎng)合。由于單例模式只允許創(chuàng)建一個(gè)對(duì)象,共享該對(duì)象可以節(jié)省內(nèi)存,并加快對(duì)象訪問速度。如Web中的配置對(duì)象、數(shù)據(jù)庫(kù)的連接池等。單例模式的結(jié)構(gòu)與實(shí)現(xiàn)單例模式是設(shè)計(jì)模式中最簡(jiǎn)單的模式之一。通常,普通類的構(gòu)造函數(shù)是公有的,外部類可以通過“new構(gòu)造函數(shù)()

5、”來生成多個(gè)實(shí)例。但是,如果將類的構(gòu)造函數(shù)設(shè)為私有的,外部類就無法調(diào)用該構(gòu)造函數(shù),也就無法生成多個(gè)實(shí)例。這時(shí)該類自身必須定義一個(gè)靜態(tài)私有實(shí)例,并向外提供一個(gè)靜態(tài)的公有函數(shù)用于創(chuàng)建或獲取該靜態(tài)私有實(shí)例。下面來分析其基本結(jié)構(gòu)和實(shí)現(xiàn)方法。1.單例模式的結(jié)構(gòu)單例模式的主要角色如下。單例類:包含一個(gè)實(shí)例且能自行創(chuàng)建這個(gè)實(shí)例的類。訪問類:使用單例的類。其結(jié)構(gòu)如圖1所示。圖1單例模式的結(jié)構(gòu)圖2.單例模式的實(shí)現(xiàn)Singleton模式通常有兩種實(shí)現(xiàn)形式。第1種:懶漢式單例該模式的特點(diǎn)是類加載時(shí)沒有生成單例,只有當(dāng)?shù)谝淮握{(diào)用getlnstance方法時(shí)才去創(chuàng)建這個(gè)單例。代碼如下保證在所有線程中同步避免類在外部被實(shí)

6、例化方法前加同步注意:如果編寫的是多線程程序,則不要?jiǎng)h除上例代碼中的關(guān)鍵字volatile和synchronized,否則將存在線程非安全的問題。如果不刪除這兩個(gè)關(guān)鍵字就能保證線程安全,但是每次訪問時(shí)都要同步,會(huì)影響性能,且消耗更多的資源,這是懶漢式單例的缺點(diǎn)。第2種:餓漢式單例該模式的特點(diǎn)是類一旦加載就創(chuàng)建一個(gè)單例,保證在調(diào)用getlnstanee方法之前單例已經(jīng)存在了。publicclassHungrySingletonprivatestaticfinalHungrySingletoninstance=newHungrySingleton();privateHungrySingleton。

7、publicstaticHungrySingletongetInstance()returninstance;餓漢式單例在類創(chuàng)建的同時(shí)就已經(jīng)創(chuàng)建好一個(gè)靜態(tài)的對(duì)象供系統(tǒng)使用,以后不再改變,所以是線程安全的,可以直接用于多線程而不會(huì)出現(xiàn)問題。單例模式的應(yīng)用實(shí)例【例1】用懶漢式單例模式模擬產(chǎn)生美國(guó)當(dāng)今總統(tǒng)對(duì)象。分析:在每一屆任期內(nèi),美國(guó)的總統(tǒng)只有一人,所以本實(shí)例適合用單例模式實(shí)現(xiàn),圖2所示是用懶漢式單例實(shí)現(xiàn)的結(jié)構(gòu)圖。publicstaticsynchmnizedPresidentgetlnstaneeLf(instaiice=null)PresidentQtelseSystem.qutpriniln

8、(有一個(gè)思統(tǒng)j不能產(chǎn)生新總統(tǒng)hrehirninstance;單例類I峽刃dem-insEiincs:President-PFtsrdent(+gednsiance():President4gelName():void誼問燙Sir)gleioiiLazy圖2美國(guó)總統(tǒng)生成器的結(jié)構(gòu)圖程序代碼如下:publicclassSingletonLazypublicstaticvoidmain(Stringargs)Presidentzt1=President.getInstance();zt1.getName();/輸出總統(tǒng)的名字Presidentzt2=President.getInstance();zt

9、2.getName();輸出總統(tǒng)的名字if(zt1=zt2)System.out.println(他們是同一人!);elseSystem.out.println(他們不是同一人!);classPresidentprivatestaticvolatilePresidentinstance=null;/保證instance在所有線程中同步/private避免類在外部被實(shí)例化privatePresident()System.out.println(產(chǎn)生一個(gè)總統(tǒng)!);publicstaticsynchronizedPresidentgetInstance()在getInstance方法上加同步if(i

10、nstance=null)instance=newPresident();elseSystem.out.println(已經(jīng)有一個(gè)總統(tǒng),不能產(chǎn)生新總統(tǒng)!);returninstance;publicvoidgetName()System.out.println(我是美國(guó)總統(tǒng):特朗普);程序運(yùn)行結(jié)果如下:產(chǎn)生一個(gè)總統(tǒng)!我是美國(guó)總統(tǒng):特朗普。已經(jīng)有一個(gè)總統(tǒng),不能產(chǎn)生新總統(tǒng)!我是美國(guó)總統(tǒng):特朗普。他們是同一人!【例2】用餓漢式單例模式模擬產(chǎn)生豬八戒對(duì)象。分析:同上例類似,豬八戒也只有一個(gè),所以本實(shí)例同樣適合用單例模式實(shí)現(xiàn)本實(shí)例由于要顯示豬八戒的圖像,所以用到了框架窗體JFrame組件,這里的豬八戒類

11、是單例類,可以將其定義成面板JPanel的子類,里面包含了標(biāo)簽,用于保存豬八戒的圖像,客戶窗體可以獲得豬八戒對(duì)象,并顯示它圖3所示是用餓漢式單例實(shí)現(xiàn)的結(jié)構(gòu)圖。圖3豬八戒生成器的結(jié)構(gòu)圖程序代碼如下:importjava.awt.*;importjavax.swing.*;publicclassSingletonEagerpublicstaticvoidmain(Stringargs)JFramejf=newJFrame(”餓漢單例模式測(cè)試);jf.setLayout(newGridLayout(1,2);ContainercontentPane=jf.getContentPane();Bajie

12、obj1=Bajie.getInstance();contentPane.add(obj1);Bajieobj2=Bajie.getInstance();contentPane.add(obj2);if(obj1=obj2)System.out.println(哋們是同一人!);elseSystem.out.println(哋們不是同一人!);jf.pack();jf.setVisible(true);jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);classBajieextendsJPanelprivatestaticBajieinstan

13、ce=newBajie();privateBajie()JLabell1=newJLabel(newImageIcon(src/Bajie.jpg);this.add(l1);publicstaticBajiegetInstance()returninstance;程序運(yùn)行結(jié)果如圖4所示。圖4豬八戒生成器的運(yùn)行結(jié)果單例模式的擴(kuò)展單例模式可擴(kuò)展為有限的多例(Multitcm)模式,這種模式可生成有限個(gè)實(shí)例并保存在ArayList中,客戶需要時(shí)可隨機(jī)獲取,如圖5所示。staticforlistadd(rwwMultiton(i)pubEicstaticMullitorigctKardomInsta

14、nce仃intviluc-(int)(MtlirardomO*nhreturn(value);缶例類Multfroniisx:ArrayLifit訪問類Client#instance:MWIicons-Multitnn(nzint)+gdRiiJidomlnslante0:Mulliltm圖5有限的多例模式的結(jié)構(gòu)圖單例模式在D源碼中的應(yīng)用DK中Runtime類使用了單例模式,源碼如下。priingnirrnninngnipiingnignirrnrrnniprini單例模式在Sprin源碼中的應(yīng)用下面介紹單例模式在Spring中的應(yīng)用。在Spring中,bean可以被定義為兩種模式:proto

15、type(多例)和singleton(單例)。singleton(單例):只有一個(gè)共享的實(shí)例存在,所有對(duì)這個(gè)bean的請(qǐng)求都會(huì)返回唯一的實(shí)例。bean實(shí)例,類似于new。prototype(多例):對(duì)這個(gè)bean的每次請(qǐng)求都會(huì)創(chuàng)建一個(gè)新的實(shí)例配置文件內(nèi)容如下:nini測(cè)試內(nèi)容如下:ingniprpipipiiiinSringrgppiinnnnngngpngpngS單例:prinnS多例:Pinnppingnnpprpnppiinnppningnningnnprpnprp運(yùn)行結(jié)果如下:?jiǎn)卫簉多例:Springbean默認(rèn)是單例模式。Spring中加載單例的過程都是在BeanFactory的g

16、etBean()方法中被定義的,其默認(rèn)的功能在AbstractBeanFactory類中實(shí)現(xiàn),主要包含兩個(gè)功能。從緩存中獲取單例Bean。Bean的實(shí)例中獲取對(duì)象。getBean()方法最終會(huì)調(diào)用AbstractBeanFactory的doGetBean()方法,源碼如下。protectedTdoGetBean(finalStringname,NullablefinalClassrequiredType,NullablefinalObjectargs,booleantypeCheckOnly)throwsBeansException對(duì)傳入的beanName稍作修改,防止有一些非法字段,然后提取

17、Bean的NamefinalStringbeanName=transformedBeanName(name);Objectbean;直接從緩存中獲取單例工廠中的objectFactory單例ObjectsharedInstance=getsingleton(beanName);if(sharedInstance!=null&args=null)if(logger.isDebugEnabled()if(isSingletonCurrentlylnCreation(beanName)logger.debug(Returningeagerlycachedinstanceofsingletonbean

18、+beanName+thatisnotfullyinitializedyet-aconsequenceofacircularreference);else返回對(duì)應(yīng)的實(shí)例,從Bean實(shí)例中獲取對(duì)象bean=getObjectForBeanInstance(sharedInstance,name,beanName,null);elsegetBean()方法不僅處理單例對(duì)象的邏輯,還處理原型對(duì)象的邏輯。繼續(xù)看getSingleton()方法的代碼實(shí)現(xiàn)。getSingleton()的工作流程:singletonObjects-earlySingletonObjects-singletonFactori

19、es-創(chuàng)建單例實(shí)例/*單例對(duì)象的緩存*/privatefinalMapvString,ObjectsingletonObjects=newConcurrentHashMap(256);protectedObjectgetSingleton(StringbeanName,booleanallowEarlyReference)首先通過名字查找這個(gè)Bean是否存在ObjectsingletonObject=this.singletonObjects.get(beanName);if(singletonObject=null&isSingletonCurrentlylnCreation(beanNam

20、e)synchronized(this.singletonObjects)查看緩存中是否存在這個(gè)BeansingletonObject=this.earlySingletonObjects.get(beanName);如果這個(gè)時(shí)候的Bean實(shí)例還為空并且允許懶加載if(singletonObjects=null&allowEarlyReference)ObjectFactorysingletonFactory=this.singletonFactories.get(beanName);if(singletonFactory!=null)singletonObject=singletonFact

21、ory.getObject();this.earlySingletonObjects.put(beanName,singletonObject);this.singletonFactories.remove(beanName);returnsingletonObject;在上面代碼片段中,synchronized(this.singletonObjects)是關(guān)鍵,但是前提條件isSingletonCurrentlylnCreation的返回值也是true,也就是這個(gè)Bean正在被創(chuàng)建。因此,第一次調(diào)用doGetBean()的時(shí)候,getSingleton()基本上都是返回null,所以會(huì)繼續(xù)

22、執(zhí)行doGetBean()方法中后面的邏輯。protectedTdoGetBean(finalStringname,NullablefinalClassrequiredType,NullablefinalObjectargs,booleantypeCheckOnly)throwsBeansException/獲取beanDefinitionfinalRootBeanDefinitionmbd=getMergedLocalBeanDefinition(beanName);checkMergedBeanDefinition(mbd,beanName,args);/Guaranteeinitiali

23、zationofbeansthatthecurrentbeandependson.StringdependsOn=mbd.getDependsOn();if(dependsOn!=null)for(Stringdep:dependsOn)if(isDependent(beanName,dep)thrownewBeanCreationException(mbd.getResourceDescription(),beanName,Circulardepends-onrelationshipbetween+beanName+and+dep+);registerDependentBean(dep,be

24、anName);trygetBean(dep);catch(NoSuchBeanDefinitionExceptionex)thrownewBeanCreationException(mbd.getResourceDescription(),beanName,+beanName+dependsonmissingbean+dep+,ex);/Createbeaninstance.if(mbd.isSingleton()sharedInstance=getSingleton(beanName,()-tryreturncreateBean(beanName,mbd,args);catch(Beans

25、Exceptionex)/Explicitlyremoveinstancefromsingletoncache:Itmighthavebeenputthere/eagerlybythecreationprocess,toallowforcircularreferenceresolution./Alsoremoveanybeansthatreceivedatemporaryreferencetothebean.destroySingleton(beanName);throwex;);bean=getObjectForBeanInstance(sharedInstance,name,beanNam

26、e,mbd);可以看到,在BeanFactory中,從XML中解析出來的相關(guān)配置信息被放在BeanDefinitionMap中,通過這個(gè)Map獲取RootBeanDefinition,然后執(zhí)行判斷語(yǔ)句if(mbd.isSingleton()o如果是單例的,則接著調(diào)用getSingleton()的重載方法,傳入mbd參數(shù)。當(dāng)從緩存中加載單例對(duì)象時(shí),會(huì)把當(dāng)前的單例對(duì)象在singletonObjects中存放一份,這樣可以保證在調(diào)用getBean()方法的時(shí)候,singletonObjects中永遠(yuǎn)只有一個(gè)實(shí)例,在獲取對(duì)象時(shí)才會(huì)給它分配內(nèi)存,既保證了內(nèi)存高效利用,又是線程安全的。publicObje

27、ctgetSingleton(StringbeanName,ObjectFactorysingletonFactory)Assert.notNull(beanName,Beannamemustnotbenull);synchronized(this.singletonObjects)/直接從緩存中獲取單例BeanObjectsingletonObject=this.singletonObjects.get(beanName);if(singletonObject=null)if(this.singletonsCurrentlylnDestruction)thrownewBeanCreationNotAllowedException(beanName,Singletonbeancreationnotallowedwhilesingletonsofthisfactoryareindestruction+(DonotrequestabeanfromaBeanFactoryinadestroymethodimplementation!);if(logger.isDebugEnabled()logger.debug(Creatingsharedinstanceofsingletonbean+beanName+);beforeSingletonCreation(bea

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論