菜鸟之路-浅谈设计模式之单例设计模式
單例設(shè)計(jì)模式
定義:確保一個(gè)類僅僅有一個(gè)實(shí)例,并且自行實(shí)例化并向整個(gè)系統(tǒng)提供這個(gè)實(shí)例。單例模式是一種經(jīng)常使用的軟件設(shè)計(jì)模式。在它的核心結(jié)構(gòu)中僅僅包括一個(gè)被稱為單例的特殊類。
通過單例模式能夠保證系統(tǒng)中一個(gè)類僅僅有一個(gè)實(shí)例并且該實(shí)例易于外界訪問,從而方便對(duì)實(shí)例個(gè)數(shù)的控制并節(jié)約系統(tǒng)資源。假設(shè)希望在系統(tǒng)中某個(gè)類的對(duì)象僅僅能存在一個(gè),單例模式是最好的解決方式。
關(guān)于單例設(shè)計(jì)模式的動(dòng)機(jī)
對(duì)于系統(tǒng)中的某些類來說。僅僅有一個(gè)實(shí)例非常重要,比如。一個(gè)系統(tǒng)中能夠存在多個(gè)打印任務(wù),可是僅僅能有一個(gè)正在工作的任務(wù);一個(gè)系統(tǒng)僅僅能有一個(gè)窗體管理器或文件系統(tǒng);一個(gè)系統(tǒng)僅僅能有一個(gè)計(jì)時(shí)工具或ID(序號(hào))生成器。如在Windows中就僅僅能打開一個(gè)任務(wù)管理器。假設(shè)不使用機(jī)制對(duì)窗體對(duì)象進(jìn)行唯一化,將彈出多個(gè)窗體。假設(shè)這些窗體顯示的內(nèi)容全然一致,則是反復(fù)對(duì)象。浪費(fèi)內(nèi)存資源;假設(shè)這些窗體顯示的內(nèi)容不一致。則意味著在某一瞬間系統(tǒng)有多個(gè)狀態(tài),與實(shí)際不符。也會(huì)給用戶帶來誤解,不知道哪一個(gè)才是真實(shí)的狀態(tài)。
因此有時(shí)確保系統(tǒng)中某個(gè)對(duì)象的唯一性即一個(gè)類僅僅能有一個(gè)實(shí)例非常重要。
怎樣保證一個(gè)類僅僅有一個(gè)實(shí)例而且這個(gè)實(shí)例易于被訪問呢?定義一個(gè)全局變量能夠確保對(duì)象隨時(shí)都能夠被訪問。但不能防止我們實(shí)例化多個(gè)對(duì)象。
一個(gè)更好的解決的方法是讓類自身負(fù)責(zé)保存它的唯一實(shí)例。這個(gè)類能夠保證沒有其它實(shí)例被創(chuàng)建。而且它能夠提供一個(gè)訪問該實(shí)例的方法。
這就是單例模式的模式動(dòng)機(jī)
關(guān)于單例設(shè)計(jì)模式的要點(diǎn)
單例模式的要點(diǎn)有三個(gè)。一是某個(gè)類僅僅能有一個(gè)實(shí)例。二是它必須自行創(chuàng)建這個(gè)實(shí)例;三是它必須自行向整個(gè)系統(tǒng)提供這個(gè)實(shí)例。從詳細(xì)實(shí)現(xiàn)角度來說,就是下面三點(diǎn):一是單例模式的類僅僅提供私有的構(gòu)造函數(shù),二是類定義中含有一個(gè)該類的靜態(tài)私有對(duì)象,三是該類提供了一個(gè)靜態(tài)的公有的函數(shù)用于創(chuàng)建或獲取它本身的靜態(tài)私有對(duì)象。
Java實(shí)例:
當(dāng)一個(gè)類的實(shí)例能夠有且僅僅能夠一個(gè)的時(shí)候就須要用到了。為什么僅僅須要有一個(gè)呢?有人說是為了節(jié)約內(nèi)存。但這僅僅是單例模式帶來的一個(gè)優(yōu)點(diǎn)。僅僅有一個(gè)實(shí)例確實(shí)降低內(nèi)存占用。但是我覺得這不是使用單例模式的理由。我覺得使用單例模式的時(shí)機(jī)是當(dāng)實(shí)例存在多個(gè)會(huì)引起程序邏輯錯(cuò)誤的時(shí)候。比方類似有序的號(hào)碼生成器這種東西。怎么能夠同意一個(gè)應(yīng)用上存在多個(gè)呢?
餓漢式單例
public class Singleton { private static Singleton singleton = new Singleton(); private Singleton(){} public static Singleton getInstance(){ return singleton; } }懶漢式單例
public class Singleton { private static Singleton singleton; private Singleton(){} public static synchronized Singleton getInstance(){ if(singleton==null){ singleton = new Singleton(); } return singleton; } } 可是這樣的單例類型在多線程中是不安全。有可能會(huì)出現(xiàn)兩個(gè)INSTANCE,為什么呢?假設(shè)當(dāng)唯一實(shí)例尚未創(chuàng)建時(shí),有兩個(gè)線程同一時(shí)候調(diào)用創(chuàng)建方法,那么它們同一時(shí)候沒有檢測(cè)到唯一實(shí)例的存在,從而同一時(shí)候各自創(chuàng)建了一個(gè)實(shí)例,這樣就有兩個(gè)實(shí)例被構(gòu)造出來,從而違反了單例模式中實(shí)例唯一的原則。 解決問題的辦法是為指示類是否已經(jīng)實(shí)例化的變量提供一個(gè)相互排斥鎖(詳見雙重鎖單例。盡管這樣會(huì)減少效率)。
比較:
餓漢式是線程安全的,在類創(chuàng)建的同一時(shí)候就已經(jīng)創(chuàng)建好一個(gè)靜態(tài)的對(duì)象供系統(tǒng)使用,以后不在改變。
懶漢式適合單線程。多線程情況下假設(shè)在創(chuàng)建實(shí)例對(duì)象時(shí)不加上synchronized則會(huì)導(dǎo)致對(duì)對(duì)象的訪問不是線程安全的。
從實(shí)現(xiàn)方式來講他們最大的差別就是懶漢式是延時(shí)載入,?
他是在須要的時(shí)候才創(chuàng)建對(duì)象,而餓漢式在載入類時(shí)創(chuàng)建實(shí)例。?
?餓漢式無需關(guān)注多線程問題、寫法簡(jiǎn)單明了、能用則用。可是它是載入類時(shí)創(chuàng)建實(shí)例、所以假設(shè)是一個(gè)工廠模式、緩存了非常多實(shí)例、那么就得考慮效率問題,由于這個(gè)類一載入則把全部實(shí)例無論用不用一塊創(chuàng)建。 懶漢式的長(zhǎng)處是延時(shí)載入、缺點(diǎn)是應(yīng)該用同步。
單例模式的長(zhǎng)處:
在內(nèi)存中僅僅有一個(gè)對(duì)象。節(jié)省內(nèi)存空間。
避免頻繁的創(chuàng)建銷毀對(duì)象,能夠提高性能。
避免對(duì)共享資源的多重占用。
能夠全局訪問。
適用場(chǎng)景:
我總結(jié)了一下我所知道的適合使用單例模式的場(chǎng)景:
須要頻繁實(shí)例化然后銷毀的對(duì)象。
創(chuàng)建對(duì)象時(shí)耗時(shí)過多或者耗資源過多,但又經(jīng)經(jīng)常使用到的對(duì)象。
有狀態(tài)的工具類對(duì)象。
頻繁訪問數(shù)據(jù)庫(kù)或文件的對(duì)象。
以及其它我沒用過的全部要求僅僅有一個(gè)對(duì)象的場(chǎng)景。
單例模式注意事項(xiàng):
僅僅能使用單例類提供的方法得到單例對(duì)象,不要使用反射。否則將會(huì)實(shí)例化一個(gè)新對(duì)象。
不要做斷開單例類對(duì)象與類中靜態(tài)引用的危急操作。
多線程使用單例使用共享資源時(shí),注意線程安全問題。
雙重鎖形式單例(懶漢式進(jìn)階版。哈哈)
public static class Singleton{private static Singleton instance=null;private Singleton(){//do something}public static Singleton getInstance(){if(instance==null){synchronized(Singleton.class){if(null==instance){instance=new Singleton();}}}return instance;} }(有些朋友搞不懂為什么要推斷兩次Instance==null,由于在多線程中第一次推斷時(shí)可能有兩個(gè)或者多個(gè)instance==null。那么在synchronized鎖里第一個(gè)instance已經(jīng)new出來了,第二個(gè)或者后面進(jìn)入的假設(shè)不推斷就會(huì)反復(fù)new對(duì)象出來,所以在里面多一層推斷確保Instance實(shí)例僅僅有一個(gè))這樣還是有一個(gè)缺點(diǎn)就是:就是在一個(gè)線程還未全然初始化該對(duì)象時(shí),而那個(gè)變量已經(jīng)顯示為被初始化,那么其它線程可能去使用這個(gè)未被全然初始化的實(shí)例,造成系統(tǒng)的崩潰。
只是這個(gè)在java5以上能夠安全執(zhí)行。
第二種完美實(shí)現(xiàn)的實(shí)現(xiàn)既線程安全又延遲載入的模式(Initialization on demand holder)使用靜態(tài)內(nèi)部類 ?演示樣例:
這樣就能保證在第一次調(diào)用getInstance()方法時(shí),才會(huì)去初始化instance實(shí)例,并且該實(shí)例被定義為static,僅僅會(huì)被初始化一次。(這樣的方法是網(wǎng)上看的,我還未用過,以后能夠試試。哈哈)
此文由本人從網(wǎng)上瀏覽總結(jié)而出。如需轉(zhuǎn)載,請(qǐng)注明出處,謝謝!
當(dāng)一個(gè)類的實(shí)例能夠有且僅僅能夠一個(gè)的時(shí)候就須要用到了。為什么僅僅須要有一個(gè)呢?有人說是為了節(jié)約內(nèi)存,但這僅僅是單例模式帶來的一個(gè)優(yōu)點(diǎn)。僅僅有一個(gè)實(shí)例確實(shí)降低內(nèi)存占用,但是我覺得這不是使用單例模式的理由。我覺得使用單例模式的時(shí)機(jī)是當(dāng)實(shí)例存在多個(gè)會(huì)引起程序邏輯錯(cuò)誤的時(shí)候。比方類似有序的號(hào)碼生成器這種東西,怎么能夠同意一個(gè)應(yīng)用上存在多個(gè)呢?
總結(jié)
以上是生活随笔為你收集整理的菜鸟之路-浅谈设计模式之单例设计模式的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 我们工作的意义到底在哪?
- 下一篇: 如何使用spring配合mybatis配