最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java多線程案例之單例模式懶漢+餓漢+枚舉

 更新時間:2022年06月02日 14:27:20   作者:??未見花聞????  
這篇文章主要介紹了Java多線程案例之單例模式懶漢+餓漢+枚舉,文章著重介紹在多線程的背景下簡單的實現(xiàn)單例模式,需要的小伙伴可以參考一下

前言:

本篇文章將介紹Java多線程中的幾個典型案例之單例模式,所謂單例模式,就是一個類只有一個實例對象,本文將著重介紹在多線程的背景下,單例模式的簡單實現(xiàn)。

1.單例模式概述

單例模式,是一種常用的軟件設(shè)計模式。在它的核心結(jié)構(gòu)中只包含一個被稱為單例的特殊類。通過單例模式可以保證系統(tǒng)中,應(yīng)用該模式的類一個類只有一個實例,即一個類只有一個對象實例。

單例模式有兩種典型的實現(xiàn),一是餓漢模式,二是懶漢模式,餓漢模式中的“餓”并不是真的表示“餓”,更加準確的來說應(yīng)該是表示“急”,那就是一個單例類還沒被使用,它的單例對象就已經(jīng)創(chuàng)建好了,而懶漢模式,要等到使用這個單例類時才創(chuàng)建單例對象。

單例模式中的單例類,只能擁有一個實例對象,又static修飾的成員是屬于類的,也就是只有一份,所以我們可以使用static修飾的成員變量保存實例對象的引用。

2.單例模式的簡單實現(xiàn)

2.1餓漢模式

由于單例模式中,一個類只能擁有一個實例對象,所以需要將類構(gòu)造方法封裝,防止類被創(chuàng)建多個實例對象,但是在使用該類時必須要得到該類的實例對象,因此我們得創(chuàng)建一個獲取該唯一實例對象的方法getInstance。

而對于該類的實例對象,在類中我們可以使用屬于類的成員變量來保存(即static成員變量)。

//單例模式 - 餓漢模式
class HungrySingleton {
    //1.使用一個變量來保存該類唯一的實例,因為單例模式在一個程序中只能擁有一個實例,由于static成員只有一份,我們可以使用static變量來保存
    private static final HungrySingleton instance = new HungrySingleton();

    //2.封裝構(gòu)造方法,防止該類被實例出新的對象
    private HungrySingleton() {}

    //3.獲取該類的唯一實例對象
    public HungrySingleton getInstance() {
        return instance;
    }
}

多線程情況下,對于上述簡單實現(xiàn)的餓漢式單例模式,只需要考慮getInstance方法是否線程安全即可,由于該方法就一句返回語句,即一次讀操作,而讀操作是線程安全的,所以getInstance方法也就是線程安全的,綜上餓漢式單例模式是線程安全的。

2.2懶漢模式

懶漢模式相比于餓漢模式,區(qū)別就是實例對象創(chuàng)建時機不同,懶漢模式需要等到第一次使用時才創(chuàng)建實例對象,所以僅僅只需要修改獲取對象的方法即可。

不考慮多線程情況,懶漢模式實現(xiàn)代碼如下:

//單例模式 - 懶漢模式
class SlackerSingleton {
    //1.使用一個變量來保存該類唯一的實例,因為單例模式在一個程序中只能擁有一個實例,由于static成員只有一份,我們可以使用static變量來保存
    //懶漢單例模式是在使用的時候創(chuàng)建對象,因此初始時對象不應(yīng)該被創(chuàng)建
    private static SlackerSingleton instance;

    //2.封裝構(gòu)造方法,防止該類被實例出新的對象
    private SlackerSingleton() {}

    //3.獲取該類的唯一對象,如果沒有就創(chuàng)建
    public SlackerSingleton getInstance() {
        if (instance == null) {
            instance = new SlackerSingleton();
        }
        return instance;
    }
}

多線程情況下,由于getInstance方法中存在兩次讀(一次判斷一次返回)操作一次寫操作(修改intsance變量的值),instance變量為初始化時(即instance=null)可能會存在多個線程進入判斷語句,這樣該類可能會被實例出多個對象,所以上述實現(xiàn)的懶漢式單例模式是線程不安全的。

造成線程不安全的代碼段為if語句里面的讀操作和instance的修改操作,所以我們需要對這段代碼進行加鎖,然后就得到了線程安全的懶漢模式:

//多線程情況下餓漢模式獲取對象時只讀不修改,所以是線程安全的
//多線程情況下懶漢模式獲取對象時存在兩次讀操作,分別為判斷instance是否為null和返回instance,除了讀操作還存在修改操作,即新建對象并使instance指向該對象
//懶漢模式對象還未初始化的時候,可能會存在多個線程進入判斷語句,會導(dǎo)致實例出多個對象,因此懶漢單例模式是線程不安全的。

//線程安全單例模式 - 懶漢模式
class SafeSlackerSingleton {
    //1.使用一個變量來保存該類唯一的實例,因為單例模式在一個程序中只能擁有一個實例,由于static成員只有一份,我們可以使用static變量來保存
    //懶漢單例模式是在使用的時候創(chuàng)建對象,因此初始時對象不應(yīng)該被創(chuàng)建
    private static SafeSlackerSingleton instance;

    //2.封裝構(gòu)造方法,防止該類被實例出新的對象
    private SafeSlackerSingleton() {}

    //3.獲取該類的唯一對象,如果沒有就創(chuàng)建
    public SafeSlackerSingleton getInstance() {
        synchronized (SafeSlackerSingleton.class) {
            if (instance == null) {
                instance = new SafeSlackerSingleton();
            }
        }
        return instance;
    }
}

但是!上述線程安全問題只出現(xiàn)在instance沒有初始化的時候,如果instance已經(jīng)初始化了,那個判斷語句就是個擺設(shè),就和餓漢模式一樣,就是線程安全的了,如果按照上面的代碼處理線程安全問題,不論instance是否已經(jīng)初始化,都要進行加鎖,因此會使鎖競爭加劇,消耗沒有必要消耗的資源,所以在加鎖前需要先判斷一下instance是否已經(jīng)初始化,如果為初始化就進行加鎖。

按照上述方案得到以下關(guān)于獲取對象的方法代碼:

    public SafeSlackerSingletonPlus getInstance() {
        //判斷instance是否初始化,如果已經(jīng)初始化了,那么該方法只有兩個讀操作,本身就是線程安全的,不需要加鎖了,這樣能減少鎖競爭,提高效率
        if (instance == null) {
            synchronized (SafeSlackerSingletonPlus.class) {
                if (instance == null) {
                    instance = new SafeSlackerSingletonPlus();
                }
            }
        }
        return instance;
    }

到這里線程安全的問題是解決了,但是別忘了編譯器它是不信任你的,它會對你寫的代碼進行優(yōu)化! 上面所寫的代碼需要判斷instance==null,而多線程情況下,很可能頻繁進行判斷,這時候線程不會去讀內(nèi)存中的數(shù)據(jù),而會直接去寄存器讀數(shù)據(jù),這時候instance值變化時,線程完全感知不到!造成內(nèi)存可見性問題,為了解決該問題需要使用關(guān)鍵字volatile修飾instance變量,防止編譯器優(yōu)化,從而保證內(nèi)存可見性。

//線程安全優(yōu)化單例模式 - 懶漢模式
class SafeSlackerSingletonPlus {
    //1.使用一個變量來保存該類唯一的實例,因為單例模式在一個程序中只能擁有一個實例,由于static成員只有一份,我們可以使用static變量來保存
    //懶漢單例模式是在使用的時候創(chuàng)建對象,因此初始時對象不應(yīng)該被創(chuàng)建
    private static volatile SafeSlackerSingletonPlus instance;

    //2.封裝構(gòu)造方法,防止該類被實例出新的對象
    private SafeSlackerSingletonPlus() {}

    //3.獲取該類的唯一對象,如果沒有就創(chuàng)建
    public SafeSlackerSingletonPlus getInstance() {
        //判斷instance是否初始化,如果已經(jīng)初始化了,那么該方法只有兩個讀操作,本身就是線程安全的,不需要加鎖了,這樣能減少鎖競爭,提高效率
        //如果線程很多,頻繁進行外層或內(nèi)層if判斷,可能會引發(fā)內(nèi)層可見性問題,因此要給instan變量加上volatile
        if (instance == null) {
            synchronized (SafeSlackerSingletonPlus.class) {
                if (instance == null) {
                    instance = new SafeSlackerSingletonPlus();
                }
            }
        }
        return instance;
    }
}

2.3枚舉實現(xiàn)單例模式

除了使用餓漢和懶漢模式還可以使用枚舉的方式實現(xiàn),在《Effective Java》書中有這樣一句話:單元素的枚舉類型已經(jīng)成為實現(xiàn)Singleton的最佳方法。 因為枚舉就是一個天然的單例,并且枚舉類型通過反射都無法獲取封裝的私有變量,非常安全。

//單元素的枚舉類型已經(jīng)成為實現(xiàn)Singleton的最佳方法
enum  EnumSingleton {
    INSTANCE;
    public void doSomething() {
        System.out.println("完成一些任務(wù)!");
    }
}

使用方式:

public class Singleton {
    public static void main(String[] args) {
        EnumSingleton.INSTANCE.doSomething();
    }
}

運行結(jié)果:

好了,有關(guān)多線程單例模式問題就討論到這里了,你學(xué)會了嗎?

到此這篇關(guān)于Java多線程案例之單例模式懶漢+餓漢+枚舉的文章就介紹到這了,更多相關(guān)Java單例模式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 模仿Spring手寫一個簡易的IOC

    模仿Spring手寫一個簡易的IOC

    這篇文章主要介紹了模仿Spring手寫一個簡易的IOC,幫助大家更好的理解和學(xué)習(xí)spring框架,感興趣的朋友可以了解下
    2020-11-11
  • Java判斷范圍型的數(shù)據(jù)是否存在重疊的方法

    Java判斷范圍型的數(shù)據(jù)是否存在重疊的方法

    遇到了個問題,同一天可以輸入多個時間段,但是每個時間段的時間不能出現(xiàn)重疊,這不就是判斷數(shù)據(jù)返回是否有重疊的變種嗎,所以本文給大家介紹了Java判斷范圍型的數(shù)據(jù)是否存在重疊的方法,需要的朋友可以參考下
    2024-07-07
  • @DS注解的使用,動態(tài)數(shù)據(jù)源,事務(wù)詳解

    @DS注解的使用,動態(tài)數(shù)據(jù)源,事務(wù)詳解

    在項目中使用多數(shù)據(jù)源時,可以借助苞米豆的dynamic-datasource-spring-boot-starter進行配置,首先需引入相應(yīng)的jar包,并在application.yml中設(shè)置主從數(shù)據(jù)源,其中一般選擇master作為默認數(shù)據(jù)源,在實現(xiàn)類中通過@DS注解指定數(shù)據(jù)源
    2024-09-09
  • java組件smartupload實現(xiàn)上傳文件功能

    java組件smartupload實現(xiàn)上傳文件功能

    這篇文章主要為大家詳細介紹了java組件smartupload實現(xiàn)上傳文件功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-10-10
  • 深入探究SpringBoot中的Elasticsearch自動配置原理及用法

    深入探究SpringBoot中的Elasticsearch自動配置原理及用法

    SpringBoot中的Elasticsearch自動配置為我們提供了一種快速集成Elasticsearch的方式,使我們可以在SpringBoot應(yīng)用程序中輕松地使用Elasticsearch,本文將介紹Spring Boot中的Elasticsearch自動配置的作用、原理和使用方法
    2023-07-07
  • Java源碼解析之平衡二叉樹

    Java源碼解析之平衡二叉樹

    在上一章的文章中,我們講到了二叉排序樹,它很好的平衡了插入與查找的效率,但二叉排序樹如果不平衡,那么查找效率就會大大降低,今天要講的這個平衡二叉樹就是一種解決這個問題的方法.需要的朋友可以參考下
    2021-05-05
  • Spring使用AspectJ注解和XML配置實現(xiàn)AOP

    Spring使用AspectJ注解和XML配置實現(xiàn)AOP

    這篇文章主要介紹了Spring使用AspectJ注解和XML配置實現(xiàn)AOP的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-10-10
  • JAVA生成pdf文件的實操教程

    JAVA生成pdf文件的實操教程

    PDF是可移植文檔格式,是一種電子文件格式,具有許多其他電子文檔格式無法相比的優(yōu)點,下面這篇文章主要給大家介紹了關(guān)于JAVA生成pdf文件的相關(guān)資料,文中通過圖文介紹的非常詳細,需要的朋友可以參考下
    2022-11-11
  • Java?Collections.sort()實現(xiàn)List排序的默認方法和自定義方法

    Java?Collections.sort()實現(xiàn)List排序的默認方法和自定義方法

    這篇文章主要介紹了Java?Collections.sort()實現(xiàn)List排序的默認方法和自定義方法,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2017-06-06
  • java8新特性之日期時間API

    java8新特性之日期時間API

    這篇文章主要介紹了java8新特性之日期時間API,文中有非常詳細的代碼示例,對正在學(xué)習(xí)java的小伙伴們有非常好的幫助,需要的朋友可以參考下
    2021-04-04

最新評論

礼泉县| 宣汉县| 长寿区| 莲花县| 凤山市| 宿松县| 保山市| 石狮市| 庆云县| 凉山| 台北市| 吴堡县| 榆林市| 焉耆| 茶陵县| 辛集市| 万源市| 千阳县| 綦江县| 元朗区| 建瓯市| 屯昌县| 永靖县| 灵丘县| 武平县| 沂源县| 呼玛县| 元谋县| 漳浦县| 临海市| 五大连池市| 澄城县| 铁力市| 扶沟县| 织金县| 平原县| 连南| 衡阳县| 松滋市| 富民县| 尚义县|