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

Java設(shè)計(jì)模式之單例模式示例詳解

 更新時(shí)間:2021年12月27日 10:02:03   作者:LL.LEBRON  
單例模式是最簡(jiǎn)單也是最基礎(chǔ)的設(shè)計(jì)模式之一,單例模式確保某個(gè)類只有一個(gè)實(shí)例,而且自行實(shí)例化并向整個(gè)系統(tǒng)提供這個(gè)實(shí)例。本文將通過一些示例代碼為大家詳細(xì)介紹一下單例模式,感興趣的可以了解一下

0.概述

為什么要使用單例模式?

在我們的系統(tǒng)中,有一些對(duì)象其實(shí)我們只需要一個(gè),比如說:線程池、緩存、對(duì)話框、注冊(cè)表、日志對(duì)象、充當(dāng)打印機(jī)、顯卡等設(shè)備驅(qū)動(dòng)程序的對(duì)象。事實(shí)上,這一類對(duì)象只能有一個(gè)實(shí)例,如果制造出多個(gè)實(shí)例就可能會(huì)導(dǎo)致一些問題的產(chǎn)生,比如:程序的行為異常、資源使用過量、或者不一致性的結(jié)果。因此這里需要用到單例模式

使用單例模式的好處?

對(duì)于頻繁使用的對(duì)象,可以省略創(chuàng)建對(duì)象所花費(fèi)的時(shí)間,這對(duì)于那些重量級(jí)對(duì)象而言,是非??捎^的一筆系統(tǒng)開銷

由于new 操作的次數(shù)減少,因而對(duì)系統(tǒng)內(nèi)存的使用頻率也會(huì)降低,這將減輕 GC 壓力,縮短 GC 停頓時(shí)間

1.餓漢式

1.1 餓漢式單例實(shí)現(xiàn)

實(shí)例會(huì)提前創(chuàng)建:

/**
* 餓漢式
*
* @author xppll
* @date 2021/12/24 21:21
*/
public class Singleton1 implements Serializable {
    //構(gòu)造私有
    private Singleton1() {
        System.out.println("private Singleton1()");
    }

    //唯一實(shí)例
    private static final Singleton1 INSTANCE = new Singleton1();

    //獲得實(shí)例方法
    public static Singleton1 getINSTANCE() {
        return INSTANCE;
    }

    //其他方法
    public static void otherMethod() {
        System.out.println("otherMethod()");
    }
}

測(cè)試:

/**
 * @author xppll
 * @date 2021/12/24 21:28
 */
public class TestSingleton {
    public static void main(String[] args) {
        //觸發(fā)Singleton1類的初始化,會(huì)為類的靜態(tài)變量賦予正確的初始值,單例對(duì)象就會(huì)被創(chuàng)建!
        Singleton1.otherMethod();
        System.out.println("-----------------------------------");
        System.out.println(Singleton1.getINSTANCE());
        System.out.println(Singleton1.getINSTANCE());
    }
}
//輸出:
private Singleton1()
otherMethod()
-----------------------------------
singleton.Singleton1@10bedb4
singleton.Singleton1@10bedb4

1.2 破壞單例的幾種情況

1.反射破壞單例

2.反序列化破壞單例

3.Unsafe破壞單例

演示:

/**
 * @author xppll
 * @date 2021/12/24 21:28
 */
public class TestSingleton {
    public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException, IOException, ClassNotFoundException {
        //觸發(fā)Singleton1類的初始化,會(huì)為類的靜態(tài)變量賦予正確的初始值,單例對(duì)象就會(huì)被創(chuàng)建!
        Singleton1.otherMethod();
        System.out.println("-----------------------------------");
        System.out.println(Singleton1.getINSTANCE());
        System.out.println(Singleton1.getINSTANCE());

        //反射破壞單例
        reflection(Singleton1.class);

        //反序列化破壞單例
        serializable(Singleton1.getINSTANCE());

        //Unsafe破壞單例
        unsafe(Singleton1.class);

    }
	//反射破壞單例
    private static void reflection(Class<?> clazz) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //得到無(wú)參
        Constructor<?> constructor = clazz.getDeclaredConstructor();
        //將此對(duì)象的 accessible 標(biāo)志設(shè)置為指示的布爾值,即設(shè)置其可訪問性
        constructor.setAccessible(true);
        //創(chuàng)建實(shí)例
        System.out.println("反射創(chuàng)建實(shí)例:" + constructor.newInstance());
    }
	//反序列化破壞單例
    private static void serializable(Object instance) throws IOException, ClassNotFoundException {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        //序列化
        oos.writeObject(instance);
        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
        //反序列化
        System.out.println("反序列化創(chuàng)建示例:" + ois.readObject());
    }
	//Unsafe破壞單例
    private static void unsafe(Class<?> clazz) throws InstantiationException {
        Object o = UnsafeUtils.getUnsafe().allocateInstance(clazz);
        System.out.println("Unsafe 創(chuàng)建實(shí)例:" + o);
    }

}

結(jié)果:

可以看出三種方式都會(huì)破壞單例!

1.3 預(yù)防單例的破壞

預(yù)防反射破壞單例

在構(gòu)造方法中加個(gè)判斷即可:

//構(gòu)造私有
private Singleton1() {
    //防止反射破壞單例
    if(INSTANCE!=null){
        throw new RuntimeException("單例對(duì)象不能重復(fù)創(chuàng)建");
    }
    System.out.println("private Singleton1()");
}

預(yù)防反序列化破壞單例

Singleton1()中重寫readResolve方法:

//重寫這個(gè)方法,如果序列化了,就會(huì)返回這個(gè),不會(huì)返回反序列化的對(duì)象
public Object readResolve(){
    return  INSTANCE;
}

Unsafe破壞單例無(wú)法預(yù)防

2.枚舉餓漢式

2.1 枚舉單例實(shí)現(xiàn)

枚舉實(shí)現(xiàn)單例:

/**
 * 枚舉實(shí)現(xiàn)單例
 *
 * @author xppll
 * @date 2021/12/24 22:23
 */
public enum Singleton2 {
    INSTANCE;

    //枚舉的構(gòu)造方法默認(rèn)是private的,可以不寫
    Singleton2() {
        System.out.println("private Singleton2()");
    }

    //重寫toString方法
    @Override
    public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }

    //獲得實(shí)例方法(這個(gè)可以不要,枚舉變量都是public的)
    public static Singleton2 getInstance() {
        return INSTANCE;
    }

    //其他方法
    public static void otherMethod() {
        System.out.println("otherMethod()");
    }
}

測(cè)試:

/**
 * @author xppll
 * @date 2021/12/24 21:28
 */
public class TestSingleton {
    public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException, IOException, ClassNotFoundException {
        //觸發(fā)Singleton2類的初始化,會(huì)為類的靜態(tài)變量賦予正確的初始值,單例對(duì)象就會(huì)被創(chuàng)建!
        Singleton2.otherMethod();
        System.out.println("-----------------------------------");
        System.out.println(Singleton2.getInstance());
        System.out.println(Singleton2.getInstance());
    }
}
//輸出:
private Singleton2()
otherMethod()
-----------------------------------
singleton.Singleton2@2de80c
singleton.Singleton2@2de80c

可以看出當(dāng)調(diào)用otherMethod()時(shí),就會(huì)觸發(fā)類的加載,枚舉對(duì)象就會(huì)創(chuàng)建,所以枚舉實(shí)現(xiàn)單例是餓漢式的

2.2 破壞單例

枚舉類實(shí)現(xiàn)單例的好處:

1.反序列化無(wú)法破壞枚舉單例

2.反射無(wú)法破壞枚舉單例

栗子:

需要先修改反射破壞代碼,枚舉需要有參構(gòu)造

public class TestSingleton {
    public static void main(String[] args) throws Exception {
        Singleton5.otherMethod();
        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
        System.out.println(Singleton5.getInstance());
        System.out.println(Singleton5.getInstance());

        //反序列化破壞單例
        serializable(Singleton2.getInstance());

        //Unsafe破壞單例
        unsafe(Singleton2.class);

        //反射破壞單例
        reflection(Singleton2.class);
    }

    private static void unsafe(Class<?> clazz) throws InstantiationException {
        Object o = UnsafeUtils.getUnsafe().allocateInstance(clazz);
        System.out.println("Unsafe 創(chuàng)建實(shí)例:" + o);
    }

    private static void serializable(Object instance) throws IOException, ClassNotFoundException {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(instance);
        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
        System.out.println("反序列化創(chuàng)建實(shí)例:" + ois.readObject());
    }

    private static void reflection(Class<?> clazz) throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
        Constructor<?> constructor = clazz.getDeclaredConstructor(String.class,int.class);
        constructor.setAccessible(true);
        System.out.println("反射創(chuàng)建實(shí)例:" + constructor.newInstance());
    }
}

結(jié)果:

可以看出

1.反射是無(wú)法創(chuàng)建枚舉對(duì)象!無(wú)法破壞枚舉單例

2.反序列化也不會(huì)破壞枚舉單例!

3.Unsafe依然會(huì)破壞!

3.懶漢式

實(shí)現(xiàn)代碼如下:

/**
 * 懶漢式
 *
 * @author xppll
 * @date 2021/12/25 08:34
 */
public class Singleton3 implements Serializable {
    //構(gòu)造私有
    private Singleton3() {
        System.out.println("private Singleton3()");
    }

    //唯一實(shí)例
    private static Singleton3 INSTANCE = null;

    public static Singleton3 getInstance() {
        //第一次調(diào)用的時(shí)候才創(chuàng)建
        if (INSTANCE == null) {
            INSTANCE = new Singleton3();
        }
        return INSTANCE;
    }

    //其他方法
    public static void otherMethod() {
        System.out.println("otherMethod()");
    }
}

測(cè)試:

/**
 * @author xppll
 * @date 2021/12/24 21:28
 */
public class TestSingleton {
    public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException, IOException, ClassNotFoundException {
        Singleton3.otherMethod();
        System.out.println("-----------------------------------");
        System.out.println(Singleton3.getInstance());
        System.out.println(Singleton3.getInstance());
    }
}

結(jié)果:

可以看出只有在第一次調(diào)用getInstance()時(shí)才會(huì)創(chuàng)建唯一的單例對(duì)象,因此是懶漢式的。

但是這種方式在多線程環(huán)境下是會(huì)有問題的,可能多個(gè)線程會(huì)同時(shí)執(zhí)行INSTANCE = new Singleton3();。因此這里需要在getInstance()方法上加上synchronized關(guān)鍵字保證多線程下的正確性:

public static synchronized Singleton3 getInstance() {
    //第一次調(diào)用的時(shí)候才創(chuàng)建
    if (INSTANCE == null) {
        INSTANCE = new Singleton3();
    }
    return INSTANCE;
}

但是這種方法是有問題的,第一次創(chuàng)建完對(duì)象后,以后的操作是不需要在加鎖的,所以這種方式會(huì)影響性能!

我們的目標(biāo)應(yīng)該是第一次創(chuàng)建單例的時(shí)候給予保護(hù),后續(xù)操作則不需要加鎖保護(hù)!

4.雙檢鎖懶漢式

針對(duì)上面的問題,這里給出第四種方法雙檢鎖懶漢式進(jìn)行優(yōu)化:

/**
 * 雙檢鎖懶漢式
 *
 * @author xppll
 * @date 2021/12/25 08:53
 */
public class Singleton4 {
    //構(gòu)造私有
    private Singleton4() {
        System.out.println("private Singleton4()");
    }

    //唯一實(shí)例
    //這里volatile的作用是保證共享變量有序性!
    private static volatile Singleton4 INSTANCE = null;

    //雙檢鎖優(yōu)化
    public static synchronized Singleton4 getInstance() {
        //實(shí)例沒創(chuàng)建,才會(huì)進(jìn)入內(nèi)部的 synchronized 代碼塊,提高性能,防止每次都加鎖
        if (INSTANCE == null) {
            //可能第一個(gè)線程在synchronized 代碼塊還沒創(chuàng)建完對(duì)象時(shí),第二個(gè)線程已經(jīng)到了這一步,所以里面還需要加上判斷
            synchronized (Singleton4.class) {
                //也許有其他線程已經(jīng)創(chuàng)建實(shí)例,所以再判斷一次
                if (INSTANCE == null) {
                    INSTANCE = new Singleton4();
                }
            }
        }
        return INSTANCE;
    }

    //其他方法
    public static void otherMethod() {
        System.out.println("otherMethod()");
    }
}

5.內(nèi)部類懶漢式

內(nèi)部類懶漢式單例實(shí)現(xiàn):

/**
 * 內(nèi)部類懶漢式
 *
 * @author xppll
 * @date 2021/12/25 09:24
 */
public class Singleton5 {

    //構(gòu)造私有
    private Singleton5() {
        System.out.println("private Singleton5()");
    }

    //靜態(tài)內(nèi)部類實(shí)現(xiàn)懶漢式單例,靜態(tài)變量的創(chuàng)建會(huì)放在靜態(tài)代碼塊里執(zhí)行,jvm會(huì)保證其線程安全
    //只有第一次用到內(nèi)部類時(shí),才會(huì)初始化創(chuàng)建單例
    private static class Holder {
        static Singleton5 INSTANCE = new Singleton5();
    }

    //獲得實(shí)例方法
    public static Singleton5 getInstance() {
        return Holder.INSTANCE;
    }

    //其他方法
    public static void otherMethod() {
        System.out.println("otherMethod()");
    }
}

測(cè)試:

/**
 * @author xppll
 * @date 2021/12/24 21:28
 */
public class TestSingleton {
    public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException, IOException, ClassNotFoundException {
        Singleton5.otherMethod();
        System.out.println("-----------------------------------");
        System.out.println(Singleton5.getInstance());
        System.out.println(Singleton5.getInstance());
    }
}

結(jié)果:

可以看出內(nèi)部類實(shí)現(xiàn)單例也是懶漢式的!

6.JDK中單例的體現(xiàn)

Runtime 體現(xiàn)了餓漢式單例

System類下的Console 體現(xiàn)了雙檢鎖懶漢式單例

Collections 中的 EmptyNavigableSet內(nèi)部類懶漢式單例

Collections 中的ReverseComparator.REVERSE_ORDER 內(nèi)部類懶漢式單例

Comparators.NaturalOrderComparator.INSTANCE 枚舉餓漢式單例

到此這篇關(guān)于Java設(shè)計(jì)模式之單例模式示例詳解的文章就介紹到這了,更多相關(guān)Java單例模式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 一篇文章帶你入門java工廠模式

    一篇文章帶你入門java工廠模式

    這篇文章主要介紹了Java工廠模式,結(jié)合實(shí)例形式詳細(xì)分析了java基本數(shù)據(jù)類型、數(shù)據(jù)類型轉(zhuǎn)換、算術(shù)運(yùn)算符、邏輯運(yùn)算符等相關(guān)原理與操作技巧,需要的朋友可以參考下
    2021-08-08
  • Java設(shè)計(jì)模式之工廠模式實(shí)現(xiàn)方法詳解

    Java設(shè)計(jì)模式之工廠模式實(shí)現(xiàn)方法詳解

    這篇文章主要介紹了Java設(shè)計(jì)模式之工廠模式實(shí)現(xiàn)方法,結(jié)合實(shí)例形式較為詳細(xì)的分析了工廠模式的分類、原理、實(shí)現(xiàn)方法與相關(guān)注意事項(xiàng),需要的朋友可以參考下
    2017-12-12
  • Mybatis自定義Sql模板語(yǔ)法問題

    Mybatis自定義Sql模板語(yǔ)法問題

    這篇文章主要介紹了Mybatis自定義Sql模板語(yǔ)法問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-09-09
  • 基于SpringBoot解析和生成CSV文件

    基于SpringBoot解析和生成CSV文件

    Apache?Commons?CSV是Apache?Commons項(xiàng)目中的一個(gè)子項(xiàng)目,專門用于處理CSV(Comma-Separated?Values,逗號(hào)分隔值)文件的Java庫(kù),CSV是一種常見的數(shù)據(jù)交換格式,本文給大家介紹了基于SpringBoot解析和生成CSV文件,需要的朋友可以參考下
    2024-12-12
  • Java服務(wù)如何調(diào)用系統(tǒng)指令、Bat腳本記錄

    Java服務(wù)如何調(diào)用系統(tǒng)指令、Bat腳本記錄

    這篇文章主要介紹了Java服務(wù)如何調(diào)用系統(tǒng)指令、Bat腳本記錄,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-06-06
  • Spring Boot 接口參數(shù)加密解密的實(shí)現(xiàn)方法

    Spring Boot 接口參數(shù)加密解密的實(shí)現(xiàn)方法

    這篇文章主要介紹了Spring Boot 接口參數(shù)加密解密的實(shí)現(xiàn)方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-03-03
  • 詳解Java數(shù)據(jù)結(jié)構(gòu)之平衡二叉樹

    詳解Java數(shù)據(jù)結(jié)構(gòu)之平衡二叉樹

    平衡二叉樹(Balanced?Binary?Tree)又被稱為AVL樹(有別于AVL算法),且具有以下性質(zhì):它是一?棵空樹或它的左右兩個(gè)子樹的高度差的絕對(duì)值不超過1,并且左右兩個(gè)子樹都是一棵平衡二叉樹。本文將詳解介紹一下平衡二叉樹的原理與實(shí)現(xiàn),需要的可以參考一下
    2022-02-02
  • Java深入了解數(shù)據(jù)結(jié)構(gòu)之棧與隊(duì)列的詳解

    Java深入了解數(shù)據(jù)結(jié)構(gòu)之棧與隊(duì)列的詳解

    這篇文章主要介紹了Java數(shù)據(jù)結(jié)構(gòu)中的棧與隊(duì)列,在Java的時(shí)候,對(duì)于棧與隊(duì)列的應(yīng)用需要熟練的掌握,這樣才能夠確保Java學(xué)習(xí)時(shí)候能夠有扎實(shí)的基礎(chǔ)能力。本文小編就來(lái)詳細(xì)說說Java中的棧與隊(duì)列,需要的朋友可以參考一下
    2022-01-01
  • Java中使用JWT生成Token進(jìn)行接口鑒權(quán)實(shí)現(xiàn)方法

    Java中使用JWT生成Token進(jìn)行接口鑒權(quán)實(shí)現(xiàn)方法

    這篇文章主要介紹了Java中使用JWT生成Token進(jìn)行接口鑒權(quán)實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • java定時(shí)任務(wù)框架elasticjob詳解

    java定時(shí)任務(wù)框架elasticjob詳解

    這篇文章主要介紹了java定時(shí)任務(wù)框架elasticjob詳解,Elastic-Job是ddframe中dd-job的作業(yè)模塊中分離出來(lái)的分布式彈性作業(yè)框架。該項(xiàng)目基于成熟的開源產(chǎn)品Quartz和Zookeeper及其客戶端Curator進(jìn)行二次開發(fā)。,需要的朋友可以參考下
    2019-06-06

最新評(píng)論

阿克| 萨迦县| 新丰县| 永寿县| 兴山县| 江永县| 梓潼县| 华蓥市| 江达县| 乐安县| 房产| 大埔县| 忻城县| 苏尼特右旗| 广饶县| 海原县| 铜山县| 绥宁县| 黄陵县| 四子王旗| 开阳县| 肇州县| 清流县| 宝兴县| 竹山县| 东兴市| 北流市| 定远县| 和平县| 隆林| 玉龙| 博乐市| 麦盖提县| 崇左市| 托里县| 翁源县| 南宫市| 尉犁县| 阳山县| 台州市| 香格里拉县|