溫馨提示×

溫馨提示×

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

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

java單例模式怎么定義

發布時間:2021-12-30 09:26:18 來源:億速云 閱讀:127 作者:iii 欄目:大數據

本篇內容介紹了“java單例模式怎么定義”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

一、單例模式定義:
單例模式確保某個類只有一個實例,而且自行實例化并向整個系統提供這個實例。在計算機系統中,線程池、緩存、日志對象、對話框、打印機、顯卡的驅動程序對象常被設計成單例。這些應用都或多或少具有資源管理器的功能。每臺計算機可以有若干個打印機,但只能有一個Printer Spooler,以避免兩個打印作業同時輸出到打印機中。每臺計算機可以有若干通信端口,系統應當集中管理這些通信端口,以避免一個通信端口同時被兩個請求同時調用??傊?,選擇單例模式就是為了避免不一致狀態,避免政出多頭。

1、經典餓漢式:

public class Singleton {
    private final static Singleton INSTANCE = new Singleton();
    private Singleton(){}
    public static Singleton getInstance(){
        return INSTANCE;
    }
}
特點:程序啟動時加載,先加載類,再初始化靜態屬性,由于后面無法再對對象進行修改,從而實現線程安全,效率相對高一些。占用內存相對多一些。

缺點:如果這個類特別龐大,初始化時將會特別緩慢,還有就是如果我們用不到這個類,它仍然會創建出來,浪費了資源。

2、經典懶漢式:

public class Singleton {
    private static Singleton singleton;
    private Singleton() {}
    public static synchronized Singleton getInstance() {
        if (singleton == null) {
            singleton = new Singleton();
        }
        return singleton;
    }
}
特點:延時加載,節約了內存。效率相對低一些。利用同步塊實現線程安全。

缺點:synchronized關鍵字是一個重鎖(對象鎖),它會每次調用getInstance(),都要對對象上鎖,事實上,只有在第一次創建對象的時候需要加鎖,之后就不需要了。

3、懶漢式變種—雙重檢查結構(不加volatile關鍵字修飾):

package cn.hzy.creationPattern.singleton;
 
public class Singleton3 {
    private static Singleton3 instance = null;
    private Singleton3(){    
    }
    public static Singleton3 getInstance(){
        if (instance == null) {
            synchronized (instance) {
            if (instance == null) {
                instance = new Singleton3();
        }
        }
        }
    return instance;
    }
}
特點:屬于懶漢式的變種,上面懶漢式的特點都有,但是這里優化了性能問題,沒有給getInstance()方法加鎖,而是只給instance = new Singleton3();加鎖,也就是說只在初始化的時候會加鎖,后面的訪問因為instance!=null,就不會加鎖。

缺點:乍一看這種模式既沒有線程安全問題,又保證了單例,貌似完美了,但是JVM在創建對象的時候有可能為了優化性能而進行指令重排,

看似簡單的一句     instance = new Singleton3();   JVM在創建對象的時候會有三個步驟:

1、給Singleton3分配一個內存空間

2、初始化Singleton3(也就是創建Singleton3對象)

3、將instance指向剛分配的內存空間地址

但是有可能JVM為了編譯的優化提高效率就有可能變成下面一種順序:

1、給Singleton3分配一個內存空間

2、將instance指向剛分配的內存空間地址

3、初始化Singleton3(也就是創建Singleton3對象)

其實這種情況在單線程情況下是毫無影響的,結果都一樣,但是如果在多線程情況下,就有可能導致錯誤。

比如:A、B兩個線程訪問getInstance()方法,A先進入第一個if判斷,然后進入synchronized塊,開始初始化Singleton3,由于發生了指令重排,將instance指向剛分配的內存空間地址(此時未創建Singleton3對象),在這個時候,B訪問getInstance()方法,B進入第一個if判斷,因為instance已經指向了一個存在的內存空間地址,即instance!=null,此時直接返回instance(未初始化),然后再調用的時候如果A還沒有初始化完畢那么就會報空指針錯誤。(概率很低)

解決方案:加上volatile關鍵字修飾,

volatile:

特性一:內存可見性,即線程A對volatile變量的修改,其他線程獲取的volatile變量都是最新的。

特性二:可以禁止指令重排序。

修改如下:將   private static Singleton3 instance = null;   改為   private static volatile Singleton3 instance = null;

4、靜態內部類:

package cn.hzy.creationPattern.singleton;
 
public class Singleton4 {
    private Singleton4() {}
    
    public static Singleton4 getInstance() {
        return SingletonFactory.instance;
    }
        
    private static class SingletonFactory {
    private static Singleton4 instance = new Singleton4();
    }
}
特點:按特征也是屬于懶漢模式,因為只會在我們需要用的時候才會創建實例對象,這里通過構造函數私有化,使用內部類來維護單例的實現,因為JVM內部的機制能夠保證當一個類被加載的時候,這個類的加載過程是線程互斥的。這樣當我們第一次調用getInstance的時候,JVM能夠幫我們保證instance只被創建一次, 并且會保證把賦值給instance的內存初始化完畢,這樣我們就不用擔心Singleton3出現的問題。同時該方法也只會在第一次調用的時候使用互斥機制,這樣就解決了低性能問題。

缺點:貌似這個就完美了,但是靜態內部類也有著一個致命的缺點,就是傳參的問題,由于是靜態內部類的形式去創建單例的,故外部無法傳遞參數進去的。

5、枚舉:

public enum Singleton {
    INSTANCE;
    public void method() {
    }
}
直接調用SingleTon.INSTANCE就是單例。

特點:創建枚舉默認就是線程安全的

優點:簡直不要太多,1、寫法簡單,對比上面的實例就能發現。2、可以防止反射攻擊。

針對上面的反射攻擊我這里簡單說一下:在上面的1、2、3、4種單例模式里面,如果不對構造函數做一些安全處理,我們可以很輕松通過反射拿到構造器并且創建不只一個實例對象,就不再是單例了。但是對于枚舉,即時你通過反射拿到構造器,在創建對象實例的時候也會報錯,因為枚舉是可以防止反射攻擊的。

怎么對構造函數做一些安全處理?

可以立一個flag,在創建一個對象實例后,改變flag的值,通過判斷拋出異常。

比如:

private static boolean flag = false;
private Singleton (){
    synchronized (Singleton .class) {
        if(false == flag){
            flag = !flag;
        } else {
            throw new RuntimeException("單例模式正在被反射攻擊?。?!");
        }  
    }
}
通過在構造函數里面增加一個判斷來保證不被反射攻擊。

“java單例模式怎么定義”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

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

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女