中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎樣淺析Java單例設計模式

發布時間:2021-12-15 09:28:05 來源:億速云 閱讀:119 作者:柒染 欄目:開發技術

本篇文章給大家分享的是有關怎樣淺析Java單例設計模式,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。

單例模式特點

1、構造器私有

2、在一個Java應用程序中,可保證只有一個實例對象

3、只提供一個供外界調用的getInstance()方法

單例模式優點

1、減少某些對象的頻繁創建,降低系統開銷和內存占用

2、外部調用不使用new關鍵字,降低系統內存的使用頻率

3、對于特殊的類,在系統中只能存在一個實例,否則系統無法正常運行,比如Controller

實現方式

這里簡單介紹兩種實現方式

餓漢式(線程安全)

/**
 * @author: xuzhilei6656
 * @create: 2021-12-12 12:07
 * @description: 單例模式(餓漢式)
 **/
public class Singleton {
    //創建實例
    private static Singleton instance = new Singleton();
 
    //私有構造器
    private Singleton(){
    }
 
    //獲取實例的靜態方法
    public static Singleton getInstance(){
        return instance;
    }
 
}

實例對象在類被加載的時候就已經完成初始化,外界調用拿到的都是這個唯一的實例對象

懶漢式

/**
 * @author: xuzhilei6656
 * @create: 2021-12-12 12:22
 * @description: 單例模式(懶漢式)
 **/
public class Singleton {
    //聲明一個變量
    private static Singleton instance;
 
    //私有構造器
    private Singleton(){
    }
 
    //獲取實例的靜態方法
    public static Singleton getInstance(){
        //如果是首次調用,實例對象還沒有被創建,就需要創建,否則都是返回已經創建過的那個對象
        if (instance == null){
            instance = new Singleton();
        }
        return instance;
    }
 
}

對比餓漢式可見,實例對象在類被加載的時候并沒有進行創建,在首次調用的時候才被創建,以后再被調用,返回的也是那個唯一的實例對象。

在多線程情況下,這種寫法存在線程安全問題,比如:線程A在執行完if判斷條件后進入阻塞狀態,此時并沒有進行對象創建,此時線程B來了,在執行完if條件后直接進行對象創建,等線程A恢復運行狀態后也會進行對象創建,這個時候就不符合單例模式了,即出現了線程不安全的問題。

解決方案:在獲取實例的靜態方法上加synchronized關鍵字,即加鎖

/**
 * @author: xuzhilei6656
 * @create: 2021-12-12 12:22
 * @description: 單例模式(懶漢式)
 **/
public class Singleton {
    //聲明一個變量
    private static Singleton instance;
 
    //私有構造器
    private Singleton(){
    }
 
    //獲取實例的靜態方法
    public static synchronized Singleton getInstance(){
        //如果是首次調用,實例對象還沒有被創建,就需要創建,否則都是返回已經創建過的那個對象
        if (instance == null){
            instance = new Singleton();
        }
        return instance;
    }
 
}

簡單粗暴,可達到我們的目的,但是每次獲取實例對象都要有加鎖操作,影響系統性能。

改進后的方案:雙重檢查

/**
 * @author: xuzhilei6656
 * @create: 2021-12-12 12:22
 * @description: 單例模式(懶漢式)
 **/
public class Singleton {
    //聲明一個變量
    private static Singleton instance;
 
    //私有構造器
    private Singleton(){
    }
 
    //獲取實例的靜態方法
    public static synchronized Singleton getInstance(){
        //第一次檢查
        if (instance == null){
            //獲取鎖
            synchronized (Singleton.class){
                //第二次檢查
                if (instance==null){
                    //兩次檢查都確定沒有已存在的實例對象,這才進行對象的創建操作
                    instance = new Singleton();
                }
            }
            
        }
        return instance;
    }
 
}

這樣不必每次獲取實例對象的時候都進行加鎖操作,只有在第一次創建對象的時候才進行加鎖操作,提高了系統性能。

但是,即使這樣有可能會出現。因為 instance = new Singleton()這行代碼在JVM中是兩個操作,賦值和初始化實例,但JVM并不保證這兩個操作的順序,有可能JVM給新對象分配了空間,直接賦值給instance變量,然后才去做初始化實例操作。比如下面這種情況

1,A,B兩個線程都進入第一個if條件

2,A線程先搶到鎖進入到synchronized代碼塊,執行了instance = new Singleton()這行代碼,然后釋放鎖,此時有可能JVM只給實例對象分配了空白的內存空間,并沒有執行初始化操作

3,B線程搶到鎖,進入到synchronized代碼塊,第二次判斷的時候發現instance不是null,直接返回使用卻發現得到的對象還沒有被初始化,于是出現了問題。

再次改進:使用volatile關鍵字修飾聲明的成員變量instance

/**
 * @author: xuzhilei6656
 * @create: 2021-12-12 12:22
 * @description: 單例模式(懶漢式)
 **/
public class Singleton {
    //聲明變量,被volatile修飾
    private volatile static Singleton instance;
 
    //私有構造器
    private Singleton(){
    }
 
    //獲取實例的靜態方法
    public static synchronized Singleton getInstance(){
        //第一次檢查
        if (instance == null){
            //獲取鎖
            synchronized (Singleton.class){
                //第二次檢查
                if (instance==null){
                    //兩次檢查都確定沒有已存在的實例對象,這才進行對象的創建操作
                    instance = new Singleton();
                }
            }
 
        }
        return instance;
    }
 
}

volatile關鍵字作用:通過volatile修飾的變量,不會被線程本地緩存,所有線程對該對象的讀寫都會第一時間同步到主內存,從而保證多個線程間該對象的準確性。

這個寫法已經比較完美了,既能保證安全的創建出唯一實例,又不會對系統性能有太大影響。

不過,還有更優的寫法:靜態內部類實現

/**
 * @author: xuzhilei6656
 * @create: 2021-12-12 15:17
 * @description: 單例模式
 **/
public class Singleton {
 
    //私有構造器
    private Singleton() {
    }
 
    //靜態內部類聲明實例
    private static class SingletonFactory{
        private static Singleton instance = new Singleton();
    }
 
    //獲取實例的靜態方法
    public static Singleton getInstance(){
        return SingletonFactory.instance;
    }
    
}

使用內部類來維護單例的實現,JVM內部的機制能夠保證當一個類被加載的時候,這個類的加載過程是線程互斥的。這樣當我們第一次調用getInstance()方法的時候,JVM能夠保證創建出唯一的實例對象,并且這個實例對象是已經被初始化完成的,就解決了上面的線程安全問題

最后一種實現單例的寫法也很完美,代碼最簡潔

通過枚舉

/**
 * @author: xuzhilei6656
 * @create: 2021-12-12 15:33
 * @description: 單例模式
 **/
public enum Singleton {
 
    //代表一個Singleton實例
    INSTANCE;
}

通過枚舉來實現單實例代碼更加簡潔,而且JVM從根本上保證實例對象的唯一性,是更簡潔、高效、安全的實現單例的方式 

以上就是怎樣淺析Java單例設計模式,小編相信有部分知識點可能是我們日常工作會見到或用到的。希望你能通過這篇文章學到更多知識。更多詳情敬請關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

大余县| 简阳市| 县级市| 龙江县| 长顺县| 安顺市| 宜丰县| 菏泽市| 嘉定区| 思茅市| 新密市| 乡宁县| 开江县| 多伦县| 上林县| 乳源| 南康市| 永福县| 大兴区| 正蓝旗| 肥城市| 田阳县| 遵义市| 墨竹工卡县| 陈巴尔虎旗| 都昌县| 老河口市| 防城港市| 长泰县| 乌拉特前旗| 望城县| 浦江县| 凤翔县| 锡林郭勒盟| 灵丘县| 白玉县| 丹阳市| 古浪县| 漠河县| 日喀则市| 永嘉县|