日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

創(chuàng)建型設(shè)計(jì)模式--單例模式

 路人甲Java 2020-06-28

一、單例模式

1、什么是單例模式

  采取一定的方法,使程序中的某個(gè)類只存在一個(gè)實(shí)例對(duì)象,且該類對(duì)外提供一個(gè)獲取該對(duì)象的方法(一般為靜態(tài)方法)。

2、單例模式分類

(1)餓漢式(2種寫(xiě)法,線程安全)
  靜態(tài)變量
  靜態(tài)代碼塊

(2)懶漢式(3種寫(xiě)法)
  線程不安全
  線程安全,同步方法
  線程安全,同步代碼塊(不推薦使用)

(3)雙重檢查(推薦使用)
(4)靜態(tài)內(nèi)部類(推薦使用)
(5)枚舉(推薦使用)

3、餓漢式單例模式(靜態(tài)常量版)

(1)步驟:
  step1:構(gòu)造器私有化(防止通過(guò)new創(chuàng)建實(shí)例對(duì)象)
  step2:在類的內(nèi)部創(chuàng)建實(shí)例對(duì)象。
  step3:向外暴露一個(gè)靜態(tài)的公共方法用于獲取實(shí)例對(duì)象。
(2)代碼實(shí)現(xiàn):

package singleton.pattern.demo1;

/**
 * 演示 餓漢式單例模式,靜態(tài)變量版
 *
 */
public class Demo {
    public static void main(String[] args) {
        Singleton singleton1 = Singleton.getSingleTon();
        Singleton singleton2 = Singleton.getSingleTon();
        System.out.println(singleton1 == singleton2); // 由于獲取的為同一個(gè)對(duì)象,所以輸出為true
    }
}

/**
 * 餓漢式單例模式,靜態(tài)變量版
 */
class Singleton {
    // 在類的內(nèi)部創(chuàng)建實(shí)例對(duì)象。使用靜態(tài)變量,只被加載一次。
    private static Singleton singleton = new Singleton();

    /**
     * 構(gòu)造器私有化(防止通過(guò)new創(chuàng)建實(shí)例對(duì)象)
     */
    private Singleton() {
    }

    /**
     * 向外暴露一個(gè)靜態(tài)的公共方法用于獲取實(shí)例對(duì)象。
     * 
     * @return 實(shí)例對(duì)象
     */
    public static Singleton getSingleTon() {
        return singleton;
    }
}

(3)優(yōu)缺點(diǎn):
  優(yōu)點(diǎn):寫(xiě)法簡(jiǎn)單,在類裝載時(shí)完成了實(shí)例化,避免線程同步問(wèn)題。
  缺點(diǎn):在類裝載前完成實(shí)例化,沒(méi)有實(shí)現(xiàn)懶加載(Lazy Loading),可能造成內(nèi)存的浪費(fèi)(比如從不使用該類時(shí)會(huì)造成內(nèi)存的浪費(fèi))。

(4)UML圖:

 

4、餓漢式單例模式(靜態(tài)代碼塊)

(1)步驟:
  step1:構(gòu)造器私有化(防止通過(guò)new創(chuàng)建實(shí)例對(duì)象)
  step2:在類的內(nèi)部聲明實(shí)例對(duì)象,并在靜態(tài)代碼塊中實(shí)例化對(duì)象。
  step3:向外暴露一個(gè)靜態(tài)的公共方法用于獲取實(shí)例對(duì)象。
(2)代碼實(shí)現(xiàn):

package singleton.pattern.demo2;

/**
 * 演示 餓漢式單例模式,靜態(tài)代碼塊版
 *
 */
public class Demo {
    public static void main(String[] args) {
        Singleton singleton1 = Singleton.getSingleTon();
        Singleton singleton2 = Singleton.getSingleTon();
        System.out.println(singleton1 == singleton2); // 由于獲取的為同一個(gè)對(duì)象,所以輸出為true
    }
}

/**
 * 餓漢式單例模式,靜態(tài)代碼塊版
 */
class Singleton {
    // 在類的內(nèi)部聲明一個(gè)實(shí)例對(duì)象
    private static Singleton singleton;

    static {
        // 在代碼塊中實(shí)例化一個(gè)對(duì)象,同樣只加載一次
        singleton = new Singleton();
    }

    /**
     * 構(gòu)造器私有化(防止通過(guò)new創(chuàng)建實(shí)例對(duì)象)
     */
    private Singleton() {
    }

    /**
     * 向外暴露一個(gè)靜態(tài)的公共方法用于獲取實(shí)例對(duì)象。
     * 
     * @return 實(shí)例對(duì)象
     */
    public static Singleton getSingleTon() {
        return singleton;
    }
}

(3)優(yōu)缺點(diǎn)同上例 餓漢式單例模式(靜態(tài)常量版)

5、懶漢式單例模式(線程不安全)

(1)步驟:
  step1:構(gòu)造器私有化(防止通過(guò)new創(chuàng)建實(shí)例對(duì)象)
  step2:在類的內(nèi)部聲明實(shí)例對(duì)象。
  step3:向外暴露一個(gè)靜態(tài)的公共方法用于獲取實(shí)例對(duì)象,在調(diào)用該方法時(shí),才去創(chuàng)建實(shí)例對(duì)象。
(2)代碼實(shí)現(xiàn):

package singleton.pattern.demo3;

/**
 * 演示 懶漢式單例模式,線程不安全版
 *
 */
public class Demo {
    public static void main(String[] args) {
        Singleton singleton1 = Singleton.getSingleTon();
        Singleton singleton2 = Singleton.getSingleTon();
        System.out.println(singleton1 == singleton2); // 由于獲取的為同一個(gè)對(duì)象,所以輸出為true
    }
}

/**
 * 懶漢式單例模式,線程不安全版
 */
class Singleton {
    // 在類的內(nèi)部聲明一個(gè)實(shí)例對(duì)象
    private static Singleton singleton;

    /**
     * 構(gòu)造器私有化(防止通過(guò)new創(chuàng)建實(shí)例對(duì)象)
     */
    private Singleton() {
    }

    /**
     * 向外暴露一個(gè)靜態(tài)的公共方法用于獲取實(shí)例對(duì)象。 當(dāng)調(diào)用該方法時(shí),才去檢查并創(chuàng)建一個(gè)實(shí)例對(duì)象。
     * 
     * @return 實(shí)例對(duì)象
     */
    public static Singleton getSingleTon() {
        if (singleton == null) {
            singleton = new Singleton();
        }
        return singleton;
    }
}

(3)優(yōu)缺點(diǎn):
  優(yōu)點(diǎn):實(shí)現(xiàn)了懶加載。
  缺點(diǎn):只能在單線程下使用,比如線程A與線程B并發(fā)執(zhí)行到 if (singleton == null), 此時(shí)便會(huì)產(chǎn)生多個(gè)實(shí)例對(duì)象。

6、懶漢式單例模式(線程安全,同步方法)

(1)步驟:
  step1:構(gòu)造器私有化(防止通過(guò)new創(chuàng)建實(shí)例對(duì)象)
  step2:在類的內(nèi)部聲明實(shí)例對(duì)象。
  step3:向外暴露一個(gè)靜態(tài)的公共方法(給靜態(tài)方法加個(gè)synchronized關(guān)鍵字,解決同步問(wèn)題)用于獲取實(shí)例對(duì)象,在調(diào)用該方法時(shí),才去創(chuàng)建實(shí)例對(duì)象。
(2)代碼實(shí)現(xiàn):

package singleton.pattern.demo4;

/**
 * 演示 懶漢式單例模式,線程安全,同步方法版
 *
 */
public class Demo {
    public static void main(String[] args) {
        Singleton singleton1 = Singleton.getSingleTon();
        Singleton singleton2 = Singleton.getSingleTon();
        System.out.println(singleton1 == singleton2); // 由于獲取的為同一個(gè)對(duì)象,所以輸出為true
    }
}

/**
 * 懶漢式單例模式,線程安全,同步方法版
 */
class Singleton {
    // 在類的內(nèi)部聲明一個(gè)實(shí)例對(duì)象
    private static Singleton singleton;

    /**
     * 構(gòu)造器私有化(防止通過(guò)new創(chuàng)建實(shí)例對(duì)象)
     */
    private Singleton() {
    }

    /**
     * 向外暴露一個(gè)靜態(tài)的公共方法用于獲取實(shí)例對(duì)象,并給方法加個(gè)synchronized關(guān)鍵字,解決同步的問(wèn)題。
     * 當(dāng)調(diào)用該方法時(shí),才去檢查并創(chuàng)建一個(gè)實(shí)例對(duì)象。
     * 
     * @return 實(shí)例對(duì)象
     */
    public static synchronized Singleton getSingleTon() {
        if (singleton == null) {
            singleton = new Singleton();
        }
        return singleton;
    }
}

(3)優(yōu)缺點(diǎn):
  優(yōu)點(diǎn):實(shí)現(xiàn)了懶加載,解決了線程不安全的問(wèn)題。
  缺點(diǎn):效率太低,每個(gè)線程想獲取實(shí)例對(duì)象時(shí),均會(huì)觸發(fā)同步方法,此時(shí)會(huì)等待前一個(gè)線程調(diào)用結(jié)束后才能使用,使效率低。

 

7、懶漢式單例模式(同步代碼塊方法,線程不一定安全)

(1)步驟:
  step1:構(gòu)造器私有化(防止通過(guò)new創(chuàng)建實(shí)例對(duì)象)
  step2:在類的內(nèi)部聲明實(shí)例對(duì)象。
  step3:向外暴露一個(gè)靜態(tài)的公共方法(在靜態(tài)方法內(nèi)部定義一個(gè)代碼塊,解決同步問(wèn)題)用于獲取實(shí)例對(duì)象,在調(diào)用該方法時(shí),才去創(chuàng)建實(shí)例對(duì)象。
(2)代碼實(shí)現(xiàn):

package singleton.pattern.demo5;

/**
 * 演示 懶漢式單例模式,線程不一定安全,同步代碼塊版
 *
 */
public class Demo {
    public static void main(String[] args) {
        Singleton singleton1 = Singleton.getSingleTon();
        Singleton singleton2 = Singleton.getSingleTon();
        System.out.println(singleton1 == singleton2); // 由于獲取的為同一個(gè)對(duì)象,所以輸出為true
    }
}

/**
 * 懶漢式單例模式,線程不一定安全,同步代碼塊版
 */
class Singleton {
    // 在類的內(nèi)部聲明一個(gè)實(shí)例對(duì)象
    private static Singleton singleton;

    /**
     * 構(gòu)造器私有化(防止通過(guò)new創(chuàng)建實(shí)例對(duì)象)
     */
    private Singleton() {
    }

    /**
     * 向外暴露一個(gè)靜態(tài)的公共方法用于獲取實(shí)例對(duì)象,在方法內(nèi)部加個(gè)同步代碼塊。 當(dāng)調(diào)用該方法時(shí),才去檢查并創(chuàng)建一個(gè)實(shí)例對(duì)象。
     * 
     * @return 實(shí)例對(duì)象
     */
    public static Singleton getSingleTon() {
        if (singleton == null) {
            synchronized (Singleton.class) {
                singleton = new Singleton();
            }
        }
        return singleton;
    }
}

(3)優(yōu)缺點(diǎn):
  優(yōu)點(diǎn):優(yōu)化了了上例 懶漢式單例模式(線程安全,同步方法) 的效率問(wèn)題。
  缺點(diǎn):能滿足大部分線程安全的情況,但是若線程A與線程B并發(fā)執(zhí)行到 if (singleton == null),此時(shí)同步代碼塊的作用就不存在了, 會(huì)產(chǎn)生多個(gè)實(shí)例對(duì)象。

 

8、雙重檢查(Double Check)

(1)步驟:
  step1:構(gòu)造器私有化(防止通過(guò)new創(chuàng)建實(shí)例對(duì)象)
  step2:在類的內(nèi)部聲明實(shí)例對(duì)象,并使用volatile關(guān)鍵字(保證可見(jiàn)性,且防止因JVM指令重排使代碼執(zhí)行順序不對(duì),從而導(dǎo)致代碼執(zhí)行有誤)。
  step3:向外暴露一個(gè)靜態(tài)的公共方法(在靜態(tài)方法內(nèi)部定義一個(gè)代碼塊,解決同步問(wèn)題)用于獲取實(shí)例對(duì)象,在調(diào)用該方法時(shí),才去創(chuàng)建實(shí)例對(duì)象。在上例 懶漢式單例模式(同步代碼塊方法,線程不一定安全) 的基礎(chǔ)上,給同步代碼塊內(nèi)部加個(gè)檢查處理。
(2)代碼實(shí)現(xiàn):

package singleton.pattern.demo6;

/**
 * 演示 單例模式,雙重檢查版
 *
 */
public class Demo {
    public static void main(String[] args) {
        Singleton singleton1 = Singleton.getSingleTon();
        Singleton singleton2 = Singleton.getSingleTon();
        System.out.println(singleton1 == singleton2); // 由于獲取的為同一個(gè)對(duì)象,所以輸出為true
    }
}

/**
 * 單例模式,雙重檢查版
 */
class Singleton {
    // 在類的內(nèi)部聲明一個(gè)實(shí)例對(duì)象
    private static volatile Singleton singleton;

    /**
     * 構(gòu)造器私有化(防止通過(guò)new創(chuàng)建實(shí)例對(duì)象)
     */
    private Singleton() {
    }

    /**
     * 向外暴露一個(gè)靜態(tài)的公共方法用于獲取實(shí)例對(duì)象,在方法內(nèi)部加個(gè)同步代碼塊,在代碼塊內(nèi)部增加一個(gè)檢查處理。 當(dāng)調(diào)用該方法時(shí),才去檢查并創(chuàng)建一個(gè)實(shí)例對(duì)象。
     * 
     * @return 實(shí)例對(duì)象
     */
    public static Singleton getSingleTon() {
        if (singleton == null) {
            synchronized (Singleton.class) {
                if (singleton == null) {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}

(3)優(yōu)缺點(diǎn):
  優(yōu)點(diǎn):線程安全,延遲加載,效率高。常用于多線程開(kāi)發(fā)。

 

9、靜態(tài)內(nèi)部類

(1)步驟:
  step1:構(gòu)造器私有化(防止通過(guò)new創(chuàng)建實(shí)例對(duì)象)
  step2:在類的內(nèi)部定義一個(gè)靜態(tài)內(nèi)部類(只有被調(diào)用時(shí),才會(huì)被加載),并在內(nèi)部類中實(shí)例化對(duì)象。
  step3:向外暴露一個(gè)靜態(tài)的公共方法,并在方法中調(diào)用靜態(tài)內(nèi)部類,用于獲取實(shí)例對(duì)象。
(2)代碼實(shí)現(xiàn):

package singleton.pattern.demo7;

/**
 * 演示 單例模式,靜態(tài)內(nèi)部類版
 *
 */
public class Demo {
    public static void main(String[] args) {
        Singleton singleton1 = Singleton.getSingleTon();
        Singleton singleton2 = Singleton.getSingleTon();
        System.out.println(singleton1 == singleton2); // 由于獲取的為同一個(gè)對(duì)象,所以輸出為true
    }
}

/**
 * 單例模式,靜態(tài)內(nèi)部類版
 */
class Singleton {
    /**
     * 構(gòu)造器私有化(防止通過(guò)new創(chuàng)建實(shí)例對(duì)象)
     */
    private Singleton() {
    }

    /**
     * 靜態(tài)內(nèi)部類,在被調(diào)用的時(shí)候才會(huì)被加載,實(shí)現(xiàn)懶加載。 且內(nèi)部使用靜態(tài)常量實(shí)例化一個(gè)對(duì)象,保證了線程安全問(wèn)題。
     */
    public static class SingleTonInstance {
        public static final Singleton INSTANCE = new Singleton();
    }

    /**
     * 向外暴露一個(gè)靜態(tài)的公共方法用于獲取實(shí)例對(duì)象,在方法內(nèi)部加個(gè)同步代碼塊,在代碼塊內(nèi)部增加一個(gè)檢查處理。 當(dāng)調(diào)用該方法時(shí),才去檢查并創(chuàng)建一個(gè)實(shí)例對(duì)象。
     * 
     * @return 實(shí)例對(duì)象
     */
    public static Singleton getSingleTon() {
        return SingleTonInstance.INSTANCE; // 調(diào)用靜態(tài)內(nèi)部類的靜態(tài)屬性
    }
}

(3)優(yōu)缺點(diǎn):
  優(yōu)點(diǎn):利用JVM的類加載機(jī)制,保證了實(shí)例化對(duì)象時(shí)只有一個(gè)線程,從而線程安全。在被調(diào)用時(shí)靜態(tài)內(nèi)部類才會(huì)被加載并實(shí)例化對(duì)象,從而實(shí)現(xiàn)懶加載,效率高。

(4)UML圖:

 

10、枚舉

(1)步驟:
  step1:定義一個(gè)枚舉類型。
  step2:調(diào)用即可
(2)代碼實(shí)現(xiàn):

package singleton.pattern;

/**
 * 演示 單例模式,枚舉版
 *
 */
public class Demo {
    public static void main(String[] args) {
        SingleTon singleton1 = SingleTon.INSTACNE;
        SingleTon singleton2 = SingleTon.INSTACNE;
        System.out.println(singleton1 == singleton2); // 由于獲取的為同一個(gè)對(duì)象,所以輸出為true
    }
}

/**
 * 單例模式,枚舉版
 */
enum SingleTon {
    INSTACNE;
    public void show() {
        System.out.println("hello world");
    }
}

(3)優(yōu)缺點(diǎn):
  優(yōu)點(diǎn):使用枚舉類型創(chuàng)建(enum本質(zhì)是個(gè)繼承java.lang.Enum類的final class),保證線程安全,且可以防止反序列化重新創(chuàng)建新的對(duì)象。

 

11、JDK中的單例模式舉例(Runtime)

(1)部分源碼

public class Runtime {
    private static Runtime currentRuntime = new Runtime();

    /**
     * Returns the runtime object associated with the current Java application.
     * Most of the methods of class <code>Runtime</code> are instance
     * methods and must be invoked with respect to the current runtime object.
     *
     * @return  the <code>Runtime</code> object associated with the current
     *          Java application.
     */
    public static Runtime getRuntime() {
        return currentRuntime;
    }

    /** Don't let anyone else instantiate this class */
    private Runtime() {} 
}

(2)可以看到上述代碼中采用的是 餓漢式單例模式(靜態(tài)變量版)。

12、單例模式使用注意

(1)當(dāng)頻繁創(chuàng)建、銷毀某個(gè)對(duì)象時(shí),可以采用單例模式。
(2)使用單例模式時(shí),需調(diào)用相關(guān)方法獲取實(shí)例,而不是通過(guò)new。
(3)當(dāng)創(chuàng)建對(duì)象消耗資源過(guò)多時(shí),但又經(jīng)常使用時(shí),可以采用單例模式創(chuàng)建。

 

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多