溫馨提示×

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

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Java單例模式的餓漢和懶漢模式怎么實(shí)現(xiàn)

發(fā)布時(shí)間:2023-04-27 14:22:21 來(lái)源:億速云 閱讀:94 作者:iii 欄目:編程語(yǔ)言

今天小編給大家分享一下Java單例模式的餓漢和懶漢模式怎么實(shí)現(xiàn)的相關(guān)知識(shí)點(diǎn),內(nèi)容詳細(xì),邏輯清晰,相信大部分人都還太了解這方面的知識(shí),所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來(lái)了解一下吧。

什么是單例模式

保證某個(gè)類(lèi)在程序中只存在一份實(shí)例,而不會(huì)創(chuàng)建多個(gè)實(shí)例,這樣就會(huì)提高效率。

在單利模式中一般只提供一個(gè)getInstance()方法來(lái)獲取實(shí)例對(duì)象,不提供setInstance()方法,目的是為了避免再實(shí)例化出其他實(shí)例對(duì)象。其中單例模式中有兩種模式一種是餓漢模式,一種是懶漢模式。

一.餓漢模式
1.餓漢模式的概念

餓漢模式就是在類(lèi)加載的時(shí)候立刻會(huì)實(shí)例化,后續(xù)使用就只會(huì)出現(xiàn)一份實(shí)例。

2.餓漢模式代碼
package thread.example;
//餓漢模式
public class HungrySingle {
//在類(lèi)加載的時(shí)候就實(shí)例化了,類(lèi)加載只有一次,所以值實(shí)例化出了一份該實(shí)例對(duì)象
    private static HungrySingle instance = new HungrySingle();
    public static HungrySingle getInstance() {
        return instance;
    }
}
3.多線程是否線程安全

在類(lèi)加載的時(shí)候就已經(jīng)實(shí)例化了,所以該實(shí)例化沒(méi)有涉及到實(shí)例化的修改操作,只是進(jìn)行讀取操作。在多線程情況下是線程安全的。

二.懶漢模式
1.懶漢模式的概念

在類(lèi)加載的時(shí)候沒(méi)有直接實(shí)例化,而是調(diào)用指定實(shí)例方法的時(shí)候再進(jìn)行實(shí)例化,這樣就能保證不想使用的時(shí)候也不會(huì)實(shí)例化。一般來(lái)說(shuō)比餓漢模式的效率高。

2.單線程情況下的懶漢模式
package thread.example;
//單線程的懶漢模式
public class LazySingle {
    private static LazySingle instance = null;
    //只有在調(diào)用該方法的時(shí)候才實(shí)例化
    public static LazySingle getInstance() {
        if(instance == null) {
            instance = new LazySingle();
        }
        return instance;
    }
}
3.多線程情況下的懶漢模式

(1)導(dǎo)致懶漢模式在多線程情況下的不安全原因

在多線程的情況下,由于可能兩個(gè)線程都會(huì)得到一份instance=null,這是因?yàn)槿绻€程1修改了自己縣城中的instance后還沒(méi)來(lái)得及修改主內(nèi)存中的instance,所導(dǎo)致線程2也實(shí)例化出了一份instance對(duì)象,這時(shí)候也就不再是單例模式了。主要導(dǎo)致該問(wèn)題的是由于這里面涉及到了對(duì)instance的修改操作,失去了原子性,為了保證原子性,我們想到了加鎖,從而實(shí)現(xiàn)線程安全問(wèn)題。

(2)解決方法代碼示例

版本1

package thread.example;
//多線程安全下的懶漢模式
    public class LazySingle {
        private LazySingle() {
    }
    private static LazySingle instance = null;
    //只有在調(diào)用該方法的時(shí)候才實(shí)例化
    public static synchronized LazySingle getInstance() {
        if (instance == null) {
            instance = new LazySingle();
        }
        return instance;
    }
}

版本1的代碼雖然保證了線程安全,但是每次調(diào)用該方法時(shí)還是會(huì)出現(xiàn)加鎖解鎖問(wèn)題,為了進(jìn)一步優(yōu)化,我們可以減小鎖的粒度來(lái)提高效率,因?yàn)榧恿随i之后也就和高并發(fā)無(wú)緣了,但我們還是想提高效率,所以才會(huì)進(jìn)行優(yōu)化。

版本2

雙重if判斷加鎖提高效率

package thread.example;
 
public class SecurityLazyModle {
    private LazySingle() {
    }
    private static volatile SecurityLazyModle instance = null;//保證內(nèi)存可見(jiàn)性,防止編譯器過(guò)度優(yōu)化(指令重排序)
    public static SecurityLazyModle getInstance() {
        if(instance == null) {
            synchronized (SecurityLazyModle.class) {
                if(instance == null) {
                    instance = new SecurityLazyModle();
                }
            }
        }
        return instance;
    }
}

版本2的解釋說(shuō)明

第一層if是為了判斷當(dāng)前是否已經(jīng)把實(shí)例創(chuàng)建出來(lái),第二層synchronized是為了使進(jìn)入當(dāng)前if中的線程來(lái)競(jìng)爭(zhēng)鎖,當(dāng)拿到鎖的線程進(jìn)入到第三層if之后判斷是否為空,不為空就是實(shí)例化對(duì)象,然后再釋放鎖,釋放鎖之后,instance已經(jīng)不為空了,后面的線程就被阻擋在了第三層if這里了,之后再來(lái)訪問(wèn)getInstance()方法,發(fā)現(xiàn)該instance已經(jīng)不為空了,也就不用再搶占鎖資源了,因?yàn)楦?jìng)爭(zhēng)鎖也消耗大量的時(shí)間。通過(guò)這樣處理,既保證了線程安全,也提高了效率。

這里使用volatile是為了防止編譯器優(yōu)化導(dǎo)致的指令重排序,在進(jìn)行new一個(gè)對(duì)象不是原子性操作,可以分為三步驟:

  1. 1.分配內(nèi)存空間

  2. 2.實(shí)例化對(duì)象

  3. 3.給變量賦值

對(duì)于上面的執(zhí)行,如果1和3先執(zhí)行了(假設(shè)2還沒(méi)有完成),在第一層if外的線程這時(shí)候判斷不為null,這時(shí)候就會(huì)直接返回該對(duì)象,但是這個(gè)對(duì)象只執(zhí)行了一半,之后使用就會(huì)導(dǎo)致線程安全問(wèn)題。

通過(guò)volatile就可以確保這3步驟必須執(zhí)行完(無(wú)論順序如何,最終都會(huì)執(zhí)行完),外面的線程才可以執(zhí)行,這時(shí)候就保證了該對(duì)象的完整性。

以上就是“Java單例模式的餓漢和懶漢模式怎么實(shí)現(xiàn)”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會(huì)為大家更新不同的知識(shí),如果還想學(xué)習(xí)更多的知識(shí),請(qǐng)關(guān)注億速云行業(yè)資訊頻道。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI