国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

設計模式-單例模式Singleton

這篇具有很好參考價值的文章主要介紹了設計模式-單例模式Singleton。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

單例模式 (Singleton) (重點)

一個類只允許創(chuàng)建一個對象(或者實例),那這個類就是一個單例類

1) 為什么要使用單例

1.表示全局唯一

如果有些數(shù)據(jù)在系統(tǒng)中應該且只能保存一份,那就應該設計為單例類:

  • 配置類:在系統(tǒng)中,我們只有一個配置文件,當配置文件被加載到內(nèi)存之后,應該被映射為一個唯一的【配置實例】
  • 全局計數(shù)器:我們使用一個全局的計數(shù)器進行數(shù)據(jù)統(tǒng)計、生成全局遞增ID等功能。若計數(shù)器不唯一,很有可能產(chǎn)生統(tǒng)計無效,ID重復等

2.處理資源訪問沖突

如果使用單個實例輸出日志,鎖【this】即可。

如果要保證JVM級別防止日志文件訪問沖突,鎖【class】即可。

如果要保證集群服務級別的防止日志文件訪問沖突,加分布式鎖即可

2) 如何實現(xiàn)一個單例

常見的單例設計模式,有如下五種寫法,在編寫單例代碼的時候要注意以下幾點:

  • 1.構造器需要私有化
  • 2.暴露一個公共的獲取單例對象的接口
  • 3.是否支持懶加載(延遲加載)
  • 4.是否線程安全

2.a) 餓漢式

在類加載的時候,instance 靜態(tài)實例就已經(jīng)創(chuàng)建并初始化好了,所以,instance 實例的創(chuàng)建過程是線程安全的

/**
 * 餓漢式單例的實現(xiàn)
 *  - 不支持懶加載
 *  - jvm保證線程安全
 */
public class EagerSingleton {

    /**
     * 當啟動程序的時候,就創(chuàng)建這個實例
     */

    // 1.持有一個jvm全局唯一的實例
    private static final EagerSingleton instance = new EagerSingleton();

    // 2.為了避免別人隨意的創(chuàng)建,需要私有化構造器
    private EagerSingleton() {
    }

    // 3.暴露一個方法,用來獲取實例
    public static EagerSingleton getInstance() {
        return instance;
    }
}

2.b) 懶漢式

懶漢式相對于餓漢式的優(yōu)勢是支持延遲加載,具體的代碼實現(xiàn)如下所示:

支持延遲加載

/**
 * 懶漢式單例的實現(xiàn)
 *  - 支持懶加載
 */
public class LazySingleton {
    
    /**
     * 當需要使用這個實例的時候,再創(chuàng)建這個實例
     */

    // 1.持有一個jvm全局唯一的實例
    private static LazySingleton instance;

    // 2.為了避免別人隨意的創(chuàng)建,需要私有化構造器
    private LazySingleton() {
    }

    // 3.暴露一個方法,用來獲取實例
    // - 懶加載-線程不安全,因為當面對大量并發(fā)請求時,有可能會有超過一個線程同時執(zhí)行此方法,是無法保證其單例的特點
    // - 加鎖:使用 synchronized,(對.class加鎖) 但是方法上加鎖會極大的降低獲取單例對象的并發(fā)度
    public static LazySingleton getInstance() {
        if (instance == null) {
            instance = new LazySingleton();
        }
        return instance;
    }
}

2.c) 雙重檢查鎖

餓漢式不支持延遲加載,懶漢式有性能問題,不支持高并發(fā)。既支持延遲加載、又支持高并發(fā)的單例實現(xiàn)方式,也就是雙重檢測鎖:

/**
 * 雙重檢查鎖單例的實現(xiàn)
 */
public class DoubleCheckLockSingleton {

    // 1.持有一個jvm全局唯一的實例
    // - 因為創(chuàng)建對象不是一個原子性操作,即使使用雙重檢查鎖,也可能在創(chuàng)建過程中產(chǎn)生半初始化狀態(tài)
    // - volatile 1.保證內(nèi)存可見 2.保存有序性
    // - jdk1.9以上,不加volatile也可以,jvm內(nèi)部處理有序性
    private static volatile DoubleCheckLockSingleton instance;

    // 2.為了避免別人隨意的創(chuàng)建,需要私有化構造器
    private DoubleCheckLockSingleton() {
    }

    // 3.暴露一個方法,用來獲取實例
    // - 第一次創(chuàng)建需要上鎖,一旦創(chuàng)建完成,就不再需要上鎖
    // - 事實上獲取單例并沒有線程安全的問題
    public static DoubleCheckLockSingleton getInstance() {
        if (instance == null) {
            synchronized (DoubleCheckLockSingleton.class) {
                // 創(chuàng)建
                if (instance == null) {
                    instance = new DoubleCheckLockSingleton();
                }
            }
        }
        return instance;
    }
}

2.d) 靜態(tài)內(nèi)部類

比雙重檢測更加簡單的實現(xiàn)方法,那就是利用 Java 的靜態(tài)內(nèi)部類。它有點類似餓漢式,但又能做到了延遲加載。

當外部類 InnerSingleton()被加載的時候,并不會創(chuàng)建 InnerSingleton的實例對象。只有當調(diào)用 getInstance() 方法時,InnerSingletonHolder 才會被加載,這個時候才會創(chuàng)建 instance實例。

/**
 * 靜態(tài)內(nèi)部類的方式實現(xiàn)單例
 */
public class InnerSingleton {

    // 1.私有化構造器
    private InnerSingleton() {
    }

    // 2.提供一個方法,獲取單例對象
    public InnerSingleton getInstance() {
        return InnerSingletonHolder.instance;
    }

    // 3.定義內(nèi)部類,來持有實例
    // - 特性:類加載的時機 --> 一個類會在第一次使用的時候被加載
    // - 實例會在內(nèi)部類加載(調(diào)用getInstance()方法之后)會創(chuàng)建
    private static class InnerSingletonHolder {
        private static final InnerSingleton instance = new InnerSingleton();
    }

}

2.e) 枚舉類

基于枚舉類型的單例實現(xiàn)。這種實現(xiàn)方式通過 Java 枚舉類型本身的特性,保證了實例創(chuàng)建的線程安全性和實例的唯一性。

/**
 * 枚舉:累加器
 */
public enum GlobalCounter {

    // 這個INSTANCE是一個單例
    // 對于枚舉類。任何一個枚舉項就是一個單例
    // 本質上就是 static final GlobalCounter instance = new GlobalCounter()
    INSTANCE;
    private AtomicLong atomicLong = new AtomicLong(0);

    public Long getNumber() {
        return atomicLong.getAndIncrement();
    }
}

2.f) 反射入侵

事實上,我們想要阻止其他人構造實例僅僅私有化構造器還是不夠的,因為我們還可以使用反射獲取私有構造器進行構造,當然使用枚舉的方式是可以解決這個問題的,對于其他的書寫方案,我們通過下邊的方式解決:

// 反射代碼
Class<DoubleCheckLockSingleton> instance = DoubleCheckLockSingleton.class;
Constructor<DoubleCheckLockSingleton> constructor = instance.getDeclaredConstructor();
constructor.setAccessible(true);

boolean flag = DoubleCheckLockSingleton.getInstance() == constructor.newInstance();
log.info("flag -> {}",flag);
/**
 * 單例的防止反射入侵的代碼實現(xiàn)
 */
public class ReflectSingleton {

    /**
     * 可以使用反射獲取私有構造器進行構造
     */
    
    private static volatile ReflectSingleton instance;

    // 為了避免別人隨意的創(chuàng)建,需要私有化構造器
    private ReflectSingleton() {
        // 升級版本 --> 不要讓人使用反射創(chuàng)建
        if (instance != null) {
            throw new RuntimeException("該對象是單例,無法創(chuàng)建多個");
        }
    }

    public static ReflectSingleton getInstance() {
        if (instance == null) {
            synchronized (ReflectSingleton.class) {
                // 創(chuàng)建
                if (instance == null) {
                    instance = new ReflectSingleton();
                }
            }
        }
        return instance;
    }
}

2.g) 序列化與反序列化安全

事實上,到目前為止,我們的單例依然是有漏洞的

/**
 * 通過序列化
 */
@Test
public void testSerialize() throws Exception {
    // 獲取單例并序列化
    SerializableSingleton instance = SerializableSingleton.getInstance();
    FileOutputStream fout = new FileOutputStream("F://singleton.txt");
    ObjectOutputStream out = new ObjectOutputStream(fout);
    out.writeObject(instance);
    // 將實例反序列化出來
    FileInputStream fin = new FileInputStream("F://singleton.txt");
    ObjectInputStream in = new ObjectInputStream(fin);
    Object o = in.readObject();
    log.info("是同一個實例嗎 {}", o == instance); // 是同一個實例嗎 false
}

在進行反序列化時,會嘗試執(zhí)行readResolve方法,并將返回值作為反序列化的結果,而不會克隆一個新的實例,保證jvm中僅僅有一個實例存在

public class Singleton implements Serializable {
    // 省略其他的內(nèi)容
    public static Singleton getInstance() {
    }
    // 需要加這么一個方法
    public Object readResolve(){
    	return singleton;
    }
}

3) 單例存在的問題

在項目中使用單例,都是用它來表示一些全局唯一類,比如配置信息類、連接池類、ID 生成器類。單例模式書寫簡潔、使用方便,在代碼中,我們不需要創(chuàng)建對象。但是,這種使用方法有點類似硬編碼(hard code),會帶來諸多問題,所以我們一般會使用spring的單例容器作為替代方案。

3.a) 無法支持面向對象編程

OOP 的三大特性是封裝、繼承、多態(tài)。單例將構造私有化,直接導致的結果就是,他無法成為其他類的父類,這就相當于直接放棄了繼承和多態(tài)的特性,也就相當于損失了可以應對未來需求變化的擴展性,以后一旦有擴展需求,比如寫一個類似的具有絕大部分相同功能的單例,我們不得不新建一個十分【雷同】的單例。文章來源地址http://www.zghlxwxcb.cn/news/detail-690500.html

到了這里,關于設計模式-單例模式Singleton的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內(nèi)容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • 《golang設計模式》第一部分·創(chuàng)建型模式-01-單例模式(Singleton)

    《golang設計模式》第一部分·創(chuàng)建型模式-01-單例模式(Singleton)

    指目標類(Class)只有一個實例對象(Object),并且向使用該對象的客戶端提供訪問單例的全局方法。 保證類只有一個實例 有方法能讓外部訪問到該實例 懶漢式 在第一次調(diào)用單例對象時創(chuàng)建該對象,這樣可以避免不必要的資源浪費 餓漢式 在程序啟動時就創(chuàng)建單例對象,這

    2024年02月14日
    瀏覽(23)
  • Singleton 單例模式簡介與 C# 示例【創(chuàng)建型】【設計模式來了】

    Singleton 單例模式簡介與 C# 示例【創(chuàng)建型】【設計模式來了】

    一句話解釋: ??單一的類,只能自己來創(chuàng)建唯一的一個對象。 單例模式(Singleton Pattern)是日常開發(fā)中最簡單的設計模式之一。這種類型的設計模式屬于 創(chuàng)建型模式 ,它提供了一種創(chuàng)建對象的最佳方式。 這種模式涉及到一個 單一的類 ,該類負責 創(chuàng)建自己的對象 ,同時

    2024年02月06日
    瀏覽(22)
  • 【java】設計模式——單例模式

    單例模式要點 : 一個類只需要一個實例化對象; 必須自行創(chuàng)建實例; 必須自行向整個系統(tǒng)提供這個實例 實現(xiàn) : 只提供 私有 構造方法; 有一個該類的 靜態(tài) 私有對象; 提供一個靜態(tài) 公有 方法用于創(chuàng)建、獲取靜態(tài)私有對象; 分析: 私有構造方法-不能隨意創(chuàng)建實例; 靜態(tài)

    2024年02月13日
    瀏覽(29)
  • Java設計模式【單例模式】

    Java設計模式【單例模式】

    單例模式(Singleton Pattern)是一種創(chuàng)建型設計模式,其主要目的是確保一個類只有一個實例,并提供對該實例的唯一訪問點。 優(yōu)點 : 提供了對唯一實例的受控訪問。 由于在系統(tǒng)內(nèi)存中只存在一個對象,因此可以節(jié)約系統(tǒng)資源。 缺點 : 單例類的擴展有很大的困難。 單例類的

    2024年02月04日
    瀏覽(27)
  • Java 設計模式——單例模式

    Java 設計模式——單例模式

    (1)單例模式 (Singleton Pattern) 是 Java 中最簡單的設計模式之一。它提供了一種創(chuàng)建對象的最佳方式。 這種模式涉及到一個單一的類,該類負責創(chuàng)建自己的對象,同時確保只有單個對象被創(chuàng)建。這個類提供了一種訪問其唯一的對象的方式,可以直接訪問,不需要實例化該類的

    2024年02月13日
    瀏覽(21)
  • Java設計模式-單例模式

    單例模式是一種設計模式,它確保一個類只能創(chuàng)建一個實例,并提供一種全局訪問這個實例的方式。在Java中,單例模式可以通過多種方式來實現(xiàn),其中最常見的是使用私有構造函數(shù)和靜態(tài)方法實現(xiàn) 在Java中,實現(xiàn)單例模式的方式有多種,其中最常見的實現(xiàn)方式包括以下幾種:

    2024年02月01日
    瀏覽(27)
  • JAVA設計模式——單例模式

    JAVA設計模式——單例模式

    單例模式是應用最廣的設計模式之一,也是程序員最熟悉的一個設計模式,使用單例模式的類必須保證只能有創(chuàng)建一個對象。 今天主要是回顧一下單例模式,主要是想搞懂以下幾個問題 為什么要使用單例? 如何實現(xiàn)一個單例? 單例存在哪些問題? 單例對象的作用域的范圍

    2024年02月16日
    瀏覽(22)
  • 設計模式篇(Java):單例模式

    設計模式篇(Java):單例模式

    上一篇:設計模式篇(Java):前言(UML類圖、七大原則) 所謂類的單例設計模式,就是采取一定的方法保證在整個的軟件系統(tǒng)中,對某個類只能存在一個對象實例,并且該類只提供一個取得其對象實例的方法(靜態(tài)方法)。 構造器私有化 (防止 new ) 類的內(nèi)部創(chuàng)建對象 向外暴露一個靜

    2024年02月11日
    瀏覽(29)
  • Java設計模式---單例 工廠 代理模式

    單例模式是設計模式中的一種,屬于創(chuàng)建型模式。在軟件工程中,單例模式確保一個類只有一個實例,并提供一個全局訪問點。這種模式常用于那些需要頻繁實例化然后引用,且創(chuàng)建新實例的開銷較大的類,例如數(shù)據(jù)庫連接池、緩存管理等。 意圖 :保證一個類僅有一個實例

    2024年01月24日
    瀏覽(28)
  • java設計模式-單例

    單例模式是一種創(chuàng)建型設計模式,它可以保證一個類只有一個實例,并提供全局訪問點。單例模式在實際開發(fā)中經(jīng)常使用,可以避免多個實例引起的資源浪費和同步問題。常見的java實現(xiàn)方式有多種。 餓漢式單例模式是指在類加載時就創(chuàng)建了單例對象,因此在調(diào)用時不需要再

    2024年01月18日
    瀏覽(26)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包