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