真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

java單例模式怎么定義

本篇內(nèi)容介紹了“java單例模式怎么定義”的有關(guān)知識,在實(shí)際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

創(chuàng)新互聯(lián)公司長期為1000多家客戶提供的網(wǎng)站建設(shè)服務(wù),團(tuán)隊(duì)從業(yè)經(jīng)驗(yàn)10年,關(guān)注不同地域、不同群體,并針對不同對象提供差異化的產(chǎn)品和服務(wù);打造開放共贏平臺,與合作伙伴共同營造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為興安盟企業(yè)提供專業(yè)的做網(wǎng)站、成都做網(wǎng)站,興安盟網(wǎng)站改版等技術(shù)服務(wù)。擁有10余年豐富建站經(jīng)驗(yàn)和眾多成功案例,為您定制開發(fā)。

一、單例模式定義:
單例模式確保某個類只有一個實(shí)例,而且自行實(shí)例化并向整個系統(tǒng)提供這個實(shí)例。在計算機(jī)系統(tǒng)中,線程池、緩存、日志對象、對話框、打印機(jī)、顯卡的驅(qū)動程序?qū)ο蟪1辉O(shè)計成單例。這些應(yīng)用都或多或少具有資源管理器的功能。每臺計算機(jī)可以有若干個打印機(jī),但只能有一個Printer Spooler,以避免兩個打印作業(yè)同時輸出到打印機(jī)中。每臺計算機(jī)可以有若干通信端口,系統(tǒng)應(yīng)當(dāng)集中管理這些通信端口,以避免一個通信端口同時被兩個請求同時調(diào)用。總之,選擇單例模式就是為了避免不一致狀態(tài),避免政出多頭。

1、經(jīng)典餓漢式:

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

缺點(diǎn):如果這個類特別龐大,初始化時將會特別緩慢,還有就是如果我們用不到這個類,它仍然會創(chuàng)建出來,浪費(fèi)了資源。

2、經(jīng)典懶漢式:

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

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

3、懶漢式變種—雙重檢查結(jié)構(gòu)(不加volatile關(guān)鍵字修飾):

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;
    }
}
特點(diǎn):屬于懶漢式的變種,上面懶漢式的特點(diǎn)都有,但是這里優(yōu)化了性能問題,沒有給getInstance()方法加鎖,而是只給instance = new Singleton3();加鎖,也就是說只在初始化的時候會加鎖,后面的訪問因?yàn)閕nstance!=null,就不會加鎖。

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

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

1、給Singleton3分配一個內(nèi)存空間

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

3、將instance指向剛分配的內(nèi)存空間地址

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

1、給Singleton3分配一個內(nèi)存空間

2、將instance指向剛分配的內(nèi)存空間地址

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

其實(shí)這種情況在單線程情況下是毫無影響的,結(jié)果都一樣,但是如果在多線程情況下,就有可能導(dǎo)致錯誤。

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

解決方案:加上volatile關(guān)鍵字修飾,

volatile:

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

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

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

4、靜態(tài)內(nèi)部類:

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();
    }
}
特點(diǎn):按特征也是屬于懶漢模式,因?yàn)橹粫谖覀冃枰玫臅r候才會創(chuàng)建實(shí)例對象,這里通過構(gòu)造函數(shù)私有化,使用內(nèi)部類來維護(hù)單例的實(shí)現(xiàn),因?yàn)镴VM內(nèi)部的機(jī)制能夠保證當(dāng)一個類被加載的時候,這個類的加載過程是線程互斥的。這樣當(dāng)我們第一次調(diào)用getInstance的時候,JVM能夠幫我們保證instance只被創(chuàng)建一次, 并且會保證把賦值給instance的內(nèi)存初始化完畢,這樣我們就不用擔(dān)心Singleton3出現(xiàn)的問題。同時該方法也只會在第一次調(diào)用的時候使用互斥機(jī)制,這樣就解決了低性能問題。

缺點(diǎn):貌似這個就完美了,但是靜態(tài)內(nèi)部類也有著一個致命的缺點(diǎn),就是傳參的問題,由于是靜態(tài)內(nèi)部類的形式去創(chuàng)建單例的,故外部無法傳遞參數(shù)進(jìn)去的。

5、枚舉:

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

特點(diǎn):創(chuàng)建枚舉默認(rèn)就是線程安全的

優(yōu)點(diǎn):簡直不要太多,1、寫法簡單,對比上面的實(shí)例就能發(fā)現(xiàn)。2、可以防止反射攻擊。

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

怎么對構(gòu)造函數(shù)做一些安全處理?

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

比如:

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

“java單例模式怎么定義”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!


分享文章:java單例模式怎么定義
標(biāo)題來源:http://weahome.cn/article/jogcge.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部