成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

JAVA單例(Singleton)實(shí)現(xiàn)的幾種方式(多線程安全)

smartlion / 1381人閱讀

摘要:缺點(diǎn)每次調(diào)用都有線程開銷延遲初始化單例默認(rèn)構(gòu)造方法為,避免用戶用構(gòu)造出新對(duì)象獲取單例的靜態(tài)工廠同步方法延遲初始化單例使用同步方法保證多線程操作只實(shí)例化一個(gè)實(shí)力單例模式。

主要分為兩種:

直接初始化

延遲初始化

直接初始化 直接初始化final靜態(tài)成員

線程安全:JVM保證final靜態(tài)成員只會(huì)被初始化一次

公有靜態(tài)成員是個(gè)final域,直接引用成員獲取單例
/**
 * 公有靜態(tài)成員是個(gè)final域
 * 直接引用成員獲取單例
 */
public class Singleton1 {
    public static final Singleton1 INSTANCE = new Singleton1();

    /**
     * 默認(rèn)構(gòu)造方法為private,避免用戶用new構(gòu)造出新對(duì)象
     */
    private Singleton1() {}

    public void someMethod() {}

    public static void main(String[] args) {
        Singleton1.INSTANCE.someMethod();
    }
}
公有的成員是個(gè)靜態(tài)工廠方法,通過該方法獲取單例。

提供了靈活性,在不改變API的前提下,可以改變?cè)擃愂欠駪?yīng)該為單例的想法。
比如改成為每個(gè)調(diào)用該方法的線程返回一個(gè)唯一的實(shí)例(ThreadLocal)

/**
 * 公有的成員是個(gè)靜態(tài)工廠方法,通過該方法獲取單例
 */
public class Singleton2 {
    private static final Singleton2 INSTANCE = new Singleton2();
    /**
     * 默認(rèn)構(gòu)造方法為private,避免用戶用new構(gòu)造出新對(duì)象
     */
    private Singleton2() {}

    /**
     * 獲取單例的靜態(tài)工廠方法
     * @return Singleton2 單例
     */
    public static Singleton2 getInstance() { return INSTANCE; }

    public void someMethod() {}

    public static void main(String[] args) {
        Singleton2.getInstance().someMethod();
    }
}
包含單個(gè)元素的枚舉類型(enum)

由枚舉類型的性質(zhì)保證枚舉常量INSTANCE是唯一實(shí)例

/**
 * 一個(gè)包含單個(gè)元素的枚舉類型
 * 枚舉類型保證每個(gè)枚舉常量都是一個(gè)單例
 */
public enum EnumSingleton {
    INSTANCE;
    public void someMethod() { /** .... */}

    public static void main(String[] args) {
        EnumSingleton.INSTANCE.someMethod();
    }
}
延遲初始化 直接在靜態(tài)工廠方法上加 synchronized。缺點(diǎn):每次調(diào)用都有線程開銷
/**
 * 延遲初始化單例
 */
public class LazyInitSingleton1 {
    private static LazyInitSingleton1 INSTANCE;
    /**
     * 默認(rèn)構(gòu)造方法為private,避免用戶用new構(gòu)造出新對(duì)象
     */
    private LazyInitSingleton1() {}

    /**
     * 獲取單例的靜態(tài)工廠同步方法
     * 延遲初始化單例
     * 使用同步方法保證多線程操作只實(shí)例化一個(gè)實(shí)力
     * @return LazyInitSingleton1 單例
     */
    public synchronized static LazyInitSingleton1 getInstance() {
        if (INSTANCE == null) {
            INSTANCE = new LazyInitSingleton1();
        }

        return INSTANCE;
    }

    public void someMethod() {}

    public static void main(String[] args) {
        Singleton2.getInstance().someMethod();
    }
}
lazy initialization holder class 模式。(參考《Effective Java》第71條:慎用延遲初始化

優(yōu)點(diǎn):避免同步方法的開銷
getInstance第一次被調(diào)用時(shí),讀取SingletonHolder.field,導(dǎo)致SingletonHolder類得到初始化

/**
 * lazy initialization holder class 模式
 * 避免同步方法的開銷
 */
public class LazyInitSingleton2 {
    private static class SingletonHolder {
        static final LazyInitSingleton2 field = computeFieldValue();
        private static LazyInitSingleton2 computeFieldValue() {
            return new LazyInitSingleton2();
        }
    }

    private LazyInitSingleton2() {}
    public static LazyInitSingleton2 getInstance() {
        return SingletonHolder.field;
    }
}
雙重檢測(cè),降低同步方法開銷。(參考《Effective Java》第71條:慎用延遲初始化)

INSTANCE 使用 volatile 修飾符:防止JVM的即時(shí)編譯器對(duì)INSTANCE = new LazyInitSingleton3()操作進(jìn)行指令重排序。

/**
 * 延遲初始化,雙重檢測(cè),降低同步方法開銷
 */
public class LazyInitSingleton3 {
    /**
     * 注意:使用了 volatile 修飾符
     */
    private static volatile LazyInitSingleton3 INSTANCE;
    private LazyInitSingleton3() {}
    public static LazyInitSingleton3 getInstance() {
        // 第一次判斷無(wú)需同步,如果 INSTANCE 已經(jīng)被初始化,
        // 就直接返回,沒有同步開銷
        if (INSTANCE == null) {
            // 如果判斷為空(多線程并發(fā)執(zhí)行 getInstance,導(dǎo)致很多線程判斷外層INSTANCE == NULL)
            synchronized (LazyInitSingleton3.class) {
                // 進(jìn)入同步后再判斷一次,
                // 保證只有一個(gè)線程賦值給 INSTANCE,
                // 后續(xù)進(jìn)來(lái)執(zhí)行的線程都會(huì)判斷 INSTANCE != NULL,不會(huì)再賦值
                if (INSTANCE == null) {
                    INSTANCE = new LazyInitSingleton3();
                }
            }
        }

        return INSTANCE;
    }
}
為什么INSTANCE要使用volatile修飾符

在JVM中,new操作做了下面3件事:

給要new的對(duì)象LazyInitSingleton3分配內(nèi)存空間

調(diào)用LazyInitSingleton3的構(gòu)造函數(shù)來(lái)初始化對(duì)象

將INSTANCE指向步驟1中分配的內(nèi)存空間

由于JVM存在指令重排序的優(yōu)化,上面第2步和第3步順序是無(wú)法保證的(1-2-3或者1-3-2)。
如果執(zhí)行步驟是1-3-2,那么假設(shè)線程A執(zhí)行到第3步,但第2步還未執(zhí)行,此時(shí)線程B調(diào)用getInstance()發(fā)現(xiàn)INSTANCE非空(但未被初始化),直接返回INSTANCE,之后線程B對(duì)INSTANCE操作可能會(huì)發(fā)生錯(cuò)誤(由于對(duì)象還未被初始化)。
volatile修飾符防止指令重排序的優(yōu)化,保證執(zhí)行順序是1-2-3。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/69447.html

相關(guān)文章

  • 深入理解單例模式

    摘要:總結(jié)我們主要介紹到了以下幾種方式實(shí)現(xiàn)單例模式餓漢方式線程安全懶漢式非線程安全和關(guān)鍵字線程安全版本懶漢式雙重檢查加鎖版本枚舉方式參考設(shè)計(jì)模式中文版第二版設(shè)計(jì)模式深入理解單例模式我是一個(gè)以架構(gòu)師為年之內(nèi)目標(biāo)的小小白。 初遇設(shè)計(jì)模式在上個(gè)寒假,當(dāng)時(shí)把每個(gè)設(shè)計(jì)模式過了一遍,對(duì)設(shè)計(jì)模式有了一個(gè)最初級(jí)的了解。這個(gè)學(xué)期借了幾本設(shè)計(jì)模式的書籍看,聽了老師的設(shè)計(jì)模式課,對(duì)設(shè)計(jì)模式算是有個(gè)更進(jìn)一步的認(rèn)識(shí)。...

    FuisonDesign 評(píng)論0 收藏0
  • 設(shè)計(jì)模式:單例模式 (關(guān)于餓漢式和懶漢式)

    摘要:在寫單例模式的代碼之前,我們先簡(jiǎn)單了解一下兩個(gè)知識(shí)點(diǎn),關(guān)于類的加載順序和關(guān)鍵字。懶漢和餓漢在程序編寫上,一般將單例模式分為兩種,分別是餓漢式和懶漢式,餓漢式在類加載時(shí)就完成了初始化,所以類加載比較慢,但獲取對(duì)象的速度快。 定義 單例模式是比較常見的一種設(shè)計(jì)模式,目的是保證一個(gè)類只能有一個(gè)實(shí)例,而且自行實(shí)例化并向整個(gè)系統(tǒng)提供這個(gè)實(shí)例,避免頻繁創(chuàng)建對(duì)象,節(jié)約內(nèi)存。 單例模式的應(yīng)用場(chǎng)景很多, 比如...

    Darkgel 評(píng)論0 收藏0
  • 設(shè)計(jì)模式系列之單例模式

    摘要:下面我們來(lái)看看看中的單例模式,中使用的是單例注冊(cè)表的特殊方式實(shí)現(xiàn)的單例模式,所以說模式是死的,需要靈活得運(yùn)用。 本文循序漸進(jìn)介紹單例模式的幾種實(shí)現(xiàn)方式,以及Jdk中使用到單例模式的例子,以及sring框架中使用到的單例模式例子。 餓漢式 package signgleton; /** * 單例模式簡(jiǎn)單的實(shí)現(xiàn) */ public class Singleton { priv...

    Jason 評(píng)論0 收藏0
  • Java設(shè)計(jì)模式---單例模式

    摘要:?jiǎn)卫J降膸追N實(shí)現(xiàn)方法具體如下懶漢模式優(yōu)點(diǎn)可以延遲加載缺點(diǎn)多線程不安全餓漢模式優(yōu)點(diǎn)多線程安全缺點(diǎn)加載類時(shí)就初始化完成無(wú)法延時(shí)加載雙重檢查優(yōu)點(diǎn)多線程安全延遲加載缺點(diǎn)同步耗時(shí)靜態(tài)內(nèi)部類優(yōu)點(diǎn)多線程安全延遲加載耗時(shí)短與雙重檢查相比用緩存實(shí)現(xiàn)優(yōu) showImg(http://7xjhi6.com1.z0.glb.clouddn.com/Java-Design-Patterns-Logo.png)...

    klivitamJ 評(píng)論0 收藏0
  • 單例模式幾種寫法

    摘要:?jiǎn)卫J揭c(diǎn)私有的構(gòu)造方法指向?qū)嵗乃接徐o態(tài)引用獲取實(shí)例對(duì)象的公有靜態(tài)方法餓漢模式非線程安全私有化構(gòu)造函數(shù)懶漢模式非線程安全私有化構(gòu)造函數(shù)雙重線程鎖檢查單例線程安全私有化構(gòu)造函數(shù)枚舉單例更多關(guān)于的文章請(qǐng)戳這里您的留言意見是對(duì)我最大的支持我的 單例模式要點(diǎn) 私有的構(gòu)造方法 指向?qū)嵗乃接徐o態(tài)引用 獲取實(shí)例對(duì)象的公有靜態(tài)方法 餓漢模式(非線程安全) public class Singl...

    Youngs 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<