欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

java面試常見模式問題---單例模式

 更新時間:2021年06月09日 11:49:53   作者:興趣使然の草帽路飛  
單例模式(Singleton Pattern)是 Java 中最簡單的設計模式之一。這種類型的設計模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對象的最佳方式

1、簡介

單例模式使⽤場景

  • 業(yè)務系統(tǒng)全局只需要⼀個對象實例,⽐如發(fā)號器、 redis 連接對象等。
  • Spring IOC容器中的 Bean 默認就是單例。
  • Spring Boot 中的 Controller、Service、Dao 層中通過 @Autowire的依賴注⼊對象默認都是單例的。

單例模式分類

  • 懶漢:就是所謂的懶加載,延遲創(chuàng)建對象,需要用的時候再創(chuàng)建對象。
  • 餓漢:與懶漢相反,提前創(chuàng)建對象。
  • 單例模式實現(xiàn)步驟:
  • 私有化構造函數(shù)
  • 提供獲取單例的方法。

2、單例模式——懶漢式

單例模式——懶漢式有以下⼏種實現(xiàn)⽅式:

/**
 * @Auther: csp1999
 * @Date: 2020/11/06/20:36
 * @Description: 單例設計模式-懶漢式
 */
public class SingletonLazy {
    // 當需要用到該實例的時候再創(chuàng)建實例對象
    private static SingletonLazy instance;
    /**
     * 構造函數(shù)私有化
     * 不能通過 new SingletonLazy() 的方式創(chuàng)建實例
     * 
     * 當需要用到該實例的時候在加載
     * 只能通過 SingletonLazy.getInstance() 這種方式獲取實例
     */
    private SingletonLazy() {
    }
    /**
     * 單例對象的方法
     */
    public void process() {
        System.out.println("方法實例化成功!");
    }
    /**
     * 方式一:
     * <p>
     * 對外暴露一個方法獲取該類的對象
     * <p>
     * 缺點:線程不安全,多線程下存在安全問題
     *
     * @return
     */
    public static SingletonLazy getInstance() {
        if (instance == null) {// 實例為null時候才創(chuàng)建
            /**
             * 線程安全問題:
             * 當某一時刻,兩個或多個線程同時判斷到instance == null成立的時候
             * 這些線程同時進入該if判斷內部執(zhí)行實例化
             * 則會新建出不止一個SingletonLazy實例
             */
            instance = new SingletonLazy();// 當需要的時候再進行實例化對象
        }
        return instance;
    }
    /**
     * 方式二:
     * 通過加synchronized鎖 保證線程安全
     *
     * 采用synchronized 對方法加鎖有很大的性能開銷
     * 因為當getInstance2()內部邏輯比較復雜的時候,在高并發(fā)條件下
     * 沒獲取到加鎖方法執(zhí)行權的線程,都得等到這個方法內的復雜邏輯執(zhí)行完后才能執(zhí)行,等待浪費時間,效率比較低
     *
     * @return
     */
    public static synchronized SingletonLazy getInstance2() {
        if (instance == null) {// 實例為null時候才創(chuàng)建
            // 方法上加synchronized鎖后可以保證線程安全
            instance = new SingletonLazy();// 當需要的時候再進行實例化對象
        }
        return instance;
    }
    /**
     * 方式三:
     * 在getInstance3()方法內,針對局部需要加鎖的代碼塊加鎖,而不是給整個方法加鎖
     *
     * 也存在缺陷:
     * @return
     */
    public static SingletonLazy getInstance3() {
        if (instance == null) {// 實例為null時候才創(chuàng)建
            // 局部加鎖后可以保證線程安全,效率較高
            // 缺陷:假設線程A和線程B
            synchronized (SingletonLazy.class){
                // 當線程A獲得鎖的執(zhí)行權的時候B等待 A執(zhí)行new SingletonLazy();實例化
                // 當A線程執(zhí)行完畢后,B再獲得執(zhí)行權,這時候還是可以實例化該對象
                instance = new SingletonLazy();// 當需要的時候再進行實例化對象
            }
        }
        return instance;
    }
}

單例模式:懶漢實現(xiàn) + 雙重檢查鎖定 + 內存模型

對于上面方式三存在的缺陷,我們可以使用雙重檢查鎖定的方式對其進行改進

/**
 * 方式三改進版本:
 * 在getInstance3()方法內,針對局部需要加鎖的代碼塊加鎖,而不是給整個方法加鎖
 *
 * DCL 雙重檢查鎖定 (Double-Checked-Locking) 在多線程情況下保持高性能
 *
 * 這是否安全? instance = new SingletonLazy(); 并不是原子性操作
 * jvm中 instance實例化內存模型流程如下:
 * 1.分配空間給對象
 * 2.在空間內創(chuàng)建對象
 * 3.將對象賦值給instance引用
 *
 * 假如出現(xiàn)如下順序錯亂的情況:
 * 線程的執(zhí)行順序為:1 -> 3 -> 2, 那么這時候會把值寫回主內存
 * 則,其他線程就會讀取到instance的最新值,但是這個是不完全的對象
 * (指令重排現(xiàn)象)
 *
 * @return
 */
public static SingletonLazy getInstance3plus() {
    if (instance == null) {// 實例為null時候才創(chuàng)建
        // 局部加鎖后可以保證線程安全,效率較高
        // 假設線程A和線程B 
        synchronized (SingletonLazy.class){// 第一重檢查
            // 當線程A獲得鎖的執(zhí)行權的時候B等待 A執(zhí)行new SingletonLazy();實例化
            // 當A線程執(zhí)行完畢后,B再獲得執(zhí)行權,這時候再判斷instance == null是否成立
            // 如果不成立,B線程無法 實例化SingletonLazy
            if (instance == null){// 第二重檢查
                instance = new SingletonLazy();// 當需要的時候再進行實例化對象
            }
        }
    }
    return instance;
}

再次升級方式三,來解決內存模型中的指令重排問題

// 添加volatile 關鍵字,禁止實例化對象時,內存模型中出現(xiàn)指令重排現(xiàn)象
private static volatile SingletonLazy instance;
/**
 * 方式三再次升級版本:
 * 在getInstance3()方法內,針對局部需要加鎖的代碼塊加鎖,而不是給整個方法加鎖
 *
 * DCL 雙重檢查鎖定 (Double-Checked-Locking) 在多線程情況下保持高性能
 *
 * 解決指令重排問題——禁止指令重排
 * @return
 */
public static SingletonLazy getInstance3plusplus() {
    if (instance == null) {// 實例為null時候才創(chuàng)建
        // 局部加鎖后可以保證線程安全,效率較高
        // 假設線程A和線程B
        synchronized (SingletonLazy.class){// 第一重檢查
            // 當線程A獲得鎖的執(zhí)行權的時候B等待 A執(zhí)行new SingletonLazy();實例化
            // 當A線程執(zhí)行完畢后,B再獲得執(zhí)行權,這時候再判斷instance == null是否成立
            // 如果不成立,B線程無法 實例化SingletonLazy
            if (instance == null){// 第二重檢查
                instance = new SingletonLazy();// 當需要的時候再進行實例化對象
            }
        }
    }
    return instance;
}

單例模式——懶漢式調用:

@Test
public void testSingletonLazy(){
    SingletonLazy.getInstance().process();
}

3、單例模式——餓漢式

/**
 * @Auther: csp1999
 * @Date: 2020/11/06/21:39
 * @Description: 單例設計模式-餓漢式
 */
public class SingletonHungry {
    // 當類加載的時候就直接實例化對象
    private static SingletonHungry instance = new SingletonHungry();
    private SingletonHungry(){}
    /**
     * 單例對象的方法
     */
    public void process() {
        System.out.println("方法實例化成功!");
    }
    public static SingletonHungry getInstance(){
        return instance;// 當類加載的時候就直接實例化對象
    }
}

單例模式——餓漢式調用:

@Test
public void testSingletonHungry(){
    SingletonHungry.getInstance().process();
}

餓漢式單例模式,當類加載的時候就直接實例化對象,因此不需要考慮線程安全問題。

  • 優(yōu)點:實現(xiàn)簡單,不需要考慮線程安全問題。
  • 缺點:不管有沒有使用該對象實例,instance對象一直占用著這段內存。

懶漢與餓漢式如何選擇?

  • 如果對象內存占用不大,且創(chuàng)建不復雜,直接使用餓漢的方式即可。
  • 其他情況均采用懶漢方式(優(yōu)選)。

總結

文章會不定時更新,有時候一天多更新幾篇,如果幫助您復習鞏固了知識點,還請支持一下,后續(xù)會億點點的更新!希望大家多多關注腳本之家的其他內容!

相關文章

  • Spring-AOP 靜態(tài)普通方法名匹配切面操作

    Spring-AOP 靜態(tài)普通方法名匹配切面操作

    這篇文章主要介紹了Spring-AOP 靜態(tài)普通方法名匹配切面操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • 日歷顯示讀出輸入的年月的java代碼

    日歷顯示讀出輸入的年月的java代碼

    這篇文章主要介紹了日歷顯示讀出輸入的年月的java代碼,有需要的朋友可以參考一下
    2013-12-12
  • Java不可不知的泛型使用示例代碼

    Java不可不知的泛型使用示例代碼

    這篇文章主要介紹了Java不可不知的泛型使用,本文通過實例代碼給大家介紹了java的泛型的基本使用,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-08-08
  • Java Math.round(),Math.ceil(),Math.floor()的區(qū)別詳解

    Java Math.round(),Math.ceil(),Math.floor()的區(qū)別詳解

    這篇文章主要介紹了Java Math.round(),Math.ceil(),Math.floor()的區(qū)別詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-08-08
  • Hikari?數(shù)據(jù)庫連接池內部源碼實現(xiàn)的小細節(jié)

    Hikari?數(shù)據(jù)庫連接池內部源碼實現(xiàn)的小細節(jié)

    這篇文章主要介紹了Hikari?數(shù)據(jù)庫連接池內部源碼實現(xiàn)的小細節(jié),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • 最安全的加密算法Bcrypt防止數(shù)據(jù)泄露詳解

    最安全的加密算法Bcrypt防止數(shù)據(jù)泄露詳解

    這篇文章主要為大家介紹了最安全的加密算法Bcrypt防止數(shù)據(jù)泄露詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-09-09
  • logback.xml動態(tài)配置程序路徑的操作

    logback.xml動態(tài)配置程序路徑的操作

    這篇文章主要介紹了logback.xml動態(tài)配置程序路徑的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • Java多線程學習筆記

    Java多線程學習筆記

    常用的實現(xiàn)多線程的兩種方式:Thread和Runnable。之所以說是“常用”,是因為在Java 5后可以通過java.util.concurrent包中的線程池來實現(xiàn)多線程
    2021-09-09
  • Java經典排序算法之希爾排序詳解

    Java經典排序算法之希爾排序詳解

    這篇文章主要為大家詳細介紹了Java經典排序算法之希爾排序,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • Java線程公平鎖和非公平鎖的差異講解

    Java線程公平鎖和非公平鎖的差異講解

    今天小編就為大家分享一篇關于Java線程公平鎖和非公平鎖的差異講解,小編覺得內容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-01-01

最新評論