Java设计模式(二) -- 单例模式
生活随笔
收集整理的這篇文章主要介紹了
Java设计模式(二) -- 单例模式
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
單例模式是Java中最廣泛應(yīng)用的設(shè)計(jì)模式之一,為創(chuàng)建對(duì)象提供了一種絕佳的方式。因此,在一些Java程序中,
一些管理器和控制器經(jīng)常被設(shè)計(jì)為單例模式。
????這種模式涉及到一個(gè)單一的類(lèi),該類(lèi)負(fù)責(zé)創(chuàng)建自己的對(duì)象,同時(shí)確保只有單個(gè)對(duì)象被創(chuàng)建。這個(gè)類(lèi)提供了一種訪問(wèn)其唯
一的對(duì)象的方式,可以直接訪問(wèn),不需要實(shí)例化該類(lèi)的對(duì)象。使用了單例模式之后,實(shí)例對(duì)象不會(huì)被重復(fù)創(chuàng)建,因此既節(jié)省
了創(chuàng)建實(shí)例對(duì)象所要的時(shí)間開(kāi)銷(xiāo),又節(jié)約了內(nèi)存空間,同時(shí)還避免了操作多個(gè)實(shí)例可能產(chǎn)生的邏輯錯(cuò)誤。對(duì)于系統(tǒng)中只需要
一個(gè)全局對(duì)象的情況,也是一種很好的解決方式。
????單例模式有以下3個(gè)特點(diǎn):1.只能創(chuàng)建一個(gè)實(shí)例2.只能自己創(chuàng)建自己的實(shí)例3.能夠給其他所有的對(duì)象提供這一實(shí)例
????單例模式主要分為餓漢式和懶漢式,其中餓漢式指的是在類(lèi)加載的時(shí)候就實(shí)例化,而懶漢式則是類(lèi)加載時(shí)先不實(shí)例化,
當(dāng)要用到實(shí)例對(duì)象時(shí)再進(jìn)行初始化。
????單例模式有多種寫(xiě)法,下面將對(duì)單例模式的寫(xiě)法進(jìn)行詳細(xì)得介紹:
????1.餓漢式單例(立即加載)
????public class Singleton1 {private static Singleton1 singleton = new Singleton1();private Singleton1() {}public static Singleton1 getInstance() {return singleton;}}
????從上面可以看到,類(lèi)的構(gòu)造函數(shù)被修飾為private,避免了被外部類(lèi)實(shí)例化,因此在Java虛擬機(jī)中,Singleton
的唯一實(shí)例只能通過(guò)getInstance()方法訪問(wèn)。同時(shí),由于static的特性,在類(lèi)加載的時(shí)候就對(duì)實(shí)例進(jìn)行了創(chuàng)建,實(shí)
例會(huì)一直存在于程序的整個(gè)生命周期中,并且在類(lèi)加載的時(shí)候只創(chuàng)建一次。但是,缺點(diǎn)也很明顯,就是沒(méi)有達(dá)到Lazy
Loading的效果。即使至始至終沒(méi)有外部類(lèi)用到這個(gè)實(shí)例,Singleton1也會(huì)創(chuàng)建出實(shí)例,造成了內(nèi)存的浪費(fèi)。
?
????2.餓漢式單例(靜態(tài)代碼塊)???
????public class Singleton2 {private static Singleton2 singleton;static {singleton = new Singleton2();}public Singleton2 getInstance() {return singleton;}} ????實(shí)際上這種方法和上面的方法很相似,把創(chuàng)建對(duì)象放在靜態(tài)代碼塊中,在類(lèi)加載時(shí)會(huì)初始化靜態(tài)代碼塊,從而創(chuàng)建 實(shí)例,優(yōu)缺點(diǎn)和上面的方法一樣。????
?
????3.懶漢式單例(線程不安全)
???? ????public class Singleton3 {private static Singleton3 singleton = null;private Singleton3() {}public static Singleton3 getInstance() {if (singleton == null) {singleton = new Singleton3();}return singleton;}} ????可以看到,在需要用到實(shí)例對(duì)象時(shí)才創(chuàng)建對(duì)象,如果對(duì)象已經(jīng)創(chuàng)建,則直接返回該對(duì)象而不是重新創(chuàng)建對(duì)象,這樣 達(dá)到了按需創(chuàng)建對(duì)象的目的,有效減少內(nèi)存損耗。但是這樣會(huì)造成線程不安全,即當(dāng)多個(gè)線程要同時(shí)創(chuàng)建實(shí)例時(shí)因?yàn)榇? 刻singleton == null,所以會(huì)給每個(gè)線程都創(chuàng)建一個(gè)實(shí)例,從而無(wú)法達(dá)到單例模式的效果。?
????4.懶漢式單例(同步鎖)???
????public class Singleton4 {private static Singleton4 singleton = null;private Singleton4() {}public static synchronized Singleton4 getInstance() {if (singleton == null) {singleton = new Singleton4();}return singleton;}} ????這個(gè)方法既達(dá)到了懶加載的效果,又解決了線程并發(fā)問(wèn)題。但是有一個(gè)缺陷,就是運(yùn)行效率太低下了。每次線程想 要?jiǎng)?chuàng)建實(shí)例時(shí),調(diào)用getInstance()都要對(duì)類(lèi)加同步鎖。synchronized修飾的方法比一般的方法要慢得多,多次調(diào) 用getInstance()會(huì)造成性能損耗較大。?
????5.懶漢式單例(雙重校驗(yàn))
????public class Singleton5 {private static Singleton5 singleton = null;private Singleton5() {}public static Singleton5 getInstance() {if (singleton == null) {synchronized (Singleton5.class) {singleton = new Singleton5();}}return singleton;}} ????使用雙重檢驗(yàn)進(jìn)一步做了優(yōu)化,可以避免整個(gè)方法被鎖,只對(duì)需要鎖的代碼部分加鎖,可以提高執(zhí)行效率。????6.懶漢式單例(volatile)
????public class Singleton6 {private volatile static Singleton6 singleton = null;private Singleton6() {}public static Singleton6 getInstance() {if (singleton == null) {synchronized (Singleton6.class) {singleton = new Singleton6();}}return singleton;}} ????volatile關(guān)鍵字排除了Java中的指令重排優(yōu)化,確保了初始化Singleton和將對(duì)象地址賦給singleton字段的 順序是確定的。?
????7.懶漢式單例(靜態(tài)內(nèi)部類(lèi))????
????public class Singleton7 {private Singleton7(){}private static class InnerClass{private static Singleton7 singleton = new Singleton7();}public static Singleton7 getInstance(){return InnerClass.singleton;}} ????這種方式利用類(lèi)加載機(jī)制確保只創(chuàng)建一個(gè)實(shí)例,因此不存在多線程并發(fā)問(wèn)題。同時(shí),在內(nèi)部類(lèi)里面去創(chuàng)建對(duì)象實(shí) 例,那么只要應(yīng)用中不使用內(nèi)部類(lèi),JVM就不會(huì)去加載這個(gè)單例類(lèi),也就不會(huì)創(chuàng)建單例對(duì)象,從而實(shí)現(xiàn)懶漢式的延遲加 載。也就是說(shuō)這種方式可以同時(shí)保證延遲加載和線程安全。????
????8.枚舉類(lèi)? ????public enum Singleton8 {singleton;public void whateverMethod(){}} ????借助JDK1.5中添加的枚舉來(lái)實(shí)現(xiàn)單例模式。不僅能避免多線程同步問(wèn)題,而且還能防止反序列化重新創(chuàng)建新的對(duì) 象。系統(tǒng)內(nèi)存中該類(lèi)只存在一個(gè)對(duì)象,節(jié)省了系統(tǒng)資源,對(duì)于一些需要頻繁創(chuàng)建銷(xiāo)毀的對(duì)象,使用單例模式可以提高系 統(tǒng)性能。但是,當(dāng)想實(shí)例化一個(gè)單例類(lèi)的時(shí)候,必須要記住使用相應(yīng)的獲取對(duì)象的方法,而不是使用new,可能會(huì)給其他 開(kāi)發(fā)人員造成困擾,特別是看不到源碼的時(shí)候。?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
總結(jié)
以上是生活随笔為你收集整理的Java设计模式(二) -- 单例模式的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Java设计模式(一) -- 工厂方法模
- 下一篇: Java设计模式(三) -- 代理模式