欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解Java單例模式的實(shí)現(xiàn)與原理剖析

 更新時(shí)間:2022年05月11日 14:11:20   作者:Bug?終結(jié)者  
單例模式是Java中最簡(jiǎn)單的設(shè)計(jì)模式之一。這種類(lèi)型的設(shè)計(jì)模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對(duì)象的最佳方式。本文將詳解單例模式的實(shí)現(xiàn)及原理剖析,需要的可以參考一下

一、什么是單例模式

單例模式(Singleton Pattern)是 Java 中最簡(jiǎn)單的設(shè)計(jì)模式之一。這種類(lèi)型的設(shè)計(jì)模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對(duì)象的最佳方式。

這種模式涉及到一個(gè)單一的類(lèi),該類(lèi)負(fù)責(zé)創(chuàng)建自己的對(duì)象,同時(shí)確保只有單個(gè)對(duì)象被創(chuàng)建。這個(gè)類(lèi)提供了一種訪問(wèn)其唯一的對(duì)象的方式,可以直接訪問(wèn),不需要實(shí)例化該類(lèi)的對(duì)象。

注意

  • 單例模式只能由一個(gè)實(shí)例對(duì)象
  • 單例類(lèi)必須自己創(chuàng)建自己的唯一實(shí)例。
  • 單例類(lèi)必須給所有其他對(duì)象提供這一實(shí)例。

二、哪些地方用到了單例模式

單例模式經(jīng)常用在需要一個(gè)實(shí)例的程序中,例如

1.Spring框架IOC容器就使用到了單例模式,默認(rèn)創(chuàng)建對(duì)象的時(shí)候?yàn)閱卫J?/p>

2.ResultBean 后端統(tǒng)一返回給前端的封裝類(lèi),這個(gè)在項(xiàng)目中是唯一的,只用一個(gè)對(duì)象進(jìn)行返回JSON給前端進(jìn)行渲染

JDK中也有單例模式的身影,例

  • Runtime 體現(xiàn)了餓漢式單例
  • Console 體現(xiàn)了雙檢鎖懶漢式單例
  • Collections 中的 EmptyNavigableSet 內(nèi)部類(lèi)懶漢式單例
  • ReverseComparator.REVERSE_ORDER 內(nèi)部類(lèi)懶漢式單例
  • Comparators.NaturalOrderComparator.INSTANCE 枚舉餓漢式單例

三、單例模式的優(yōu)缺點(diǎn)

優(yōu)點(diǎn)

提供了對(duì)唯一實(shí)例的訪問(wèn)

可以節(jié)約系統(tǒng)資源,提高系統(tǒng)的性能,減少不必要的內(nèi)存開(kāi)銷(xiāo)

允許可變數(shù)目的實(shí)例(多例類(lèi))

缺點(diǎn)

擴(kuò)展困難(缺少抽象層)

單例類(lèi)的職責(zé)過(guò)重

由于自動(dòng)垃圾回收機(jī)制,可能會(huì)導(dǎo)致共享的單例對(duì)象的狀態(tài)丟失

四、手寫(xiě)單例模式

餓漢式

package com.wanshi.single;

//餓漢式單例
public class Hungry {


    //會(huì)造成資源浪費(fèi),占用CPU
    private byte[] data1 = new byte[1024*1024];
    private byte[] data2 = new byte[1024*1024];
    private byte[] data3 = new byte[1024*1024];
    private byte[] data4 = new byte[1024*1024];


    private Hungry() {
        System.out.println("Hungry init...");
    }


    private static Hungry hungry = new Hungry();

    public static Hungry getInstance() {
        return hungry;
    }
}

class Test {
	public static void main(String[] args) {
        Hungry hungry = Hungry.getInstance();
        Hungry hungry2 = Hungry.getInstance();
        System.out.println(hungry);
        System.out.println(hungry2);
    }
}

枚舉餓漢式

package com.wanshi.single;

import java.lang.reflect.Constructor;

// enum 是一個(gè)class類(lèi)
public enum EnumSingle {

    INSTANCE;

    public static EnumSingle getInstance() {
        return INSTANCE;
    }
}

class Test {

    public static void main(String[] args) throws Exception{
        EnumSingle instance1 = EnumSingle.INSTANCE;
        Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(String.class, int.class);
        declaredConstructor.setAccessible(true);

        EnumSingle instance2 = declaredConstructor.newInstance();

        System.out.println(instance1);
        System.out.println(instance2);
    }
}

在這里自行下載jad編譯工具即可

枚舉類(lèi)最后反編譯源碼

jad工具反編譯

jad -sjava EnumSingle.class

// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3) 
// Source File Name:   EnumSingle.java

package com.wanshi.single;


public final class EnumSingle extends Enum
{

    public static EnumSingle[] values()
    {
        return (EnumSingle[])$VALUES.clone();
    }

    public static EnumSingle valueOf(String name)
    {
        return (EnumSingle)Enum.valueOf(com/wanshi/single/EnumSingle, name);
    }

    private EnumSingle(String s, int i)
    {
        super(s, i);
    }

    public static EnumSingle getInstance()
    {
        return INSTANCE;
    }

    public static final EnumSingle INSTANCE;
    private static final EnumSingle $VALUES[];

    static 
    {
        INSTANCE = new EnumSingle("INSTANCE", 0);
        $VALUES = (new EnumSingle[] {
            INSTANCE
        });
    }
}

DCL懶漢式

package com.wanshi.single;

public class Lazy {

    private static Lazy lazy;

    public static Lazy getInterface() {
        synchronized (Lazy.class) {
            if (lazy == null) {
                lazy = new Lazy();
            }
        }
        return lazy;
    }

    public static void main(String[] args) {
        Lazy lazy = Lazy.getInterface();
        Lazy lazy2 = Lazy.getInterface();
        System.out.println(lazy);
        System.out.println(lazy2);
    }
}

雙檢鎖懶漢式

package com.wanshi.single;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

public class LazyMan {


    private static boolean flag = false;

    private LazyMan() {
        synchronized (this) {
            if (!flag) {
                flag = true;
            } else {
                throw new RuntimeException("不要試圖通過(guò)反射破壞對(duì)象");
            }
        }
    }

    private volatile static LazyMan lazyMan;

    //雙重檢查鎖,懶漢式(DCL懶漢式)
    public static LazyMan getInstance() {
        if (lazyMan == null) {
            synchronized (LazyMan.class) {
                if (lazyMan == null) {
                    //不是原子性操作,1.分配內(nèi)存空間,2.執(zhí)行構(gòu)造方法,3.把對(duì)象指向這個(gè)空間 指令重排可能會(huì)發(fā)生   加上volatile關(guān)閉指令重排
                    lazyMan = new LazyMan();
                }
            }
        }
        return lazyMan;
    }

    public static void main(String[] args) throws Exception {
//        LazyMan lazyMan1 = LazyMan.getInstance();

        Field flag = LazyMan.class.getDeclaredField("flag");
        flag.setAccessible(true);


        Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);

        declaredConstructor.setAccessible(true);
        LazyMan lazyMan1 = declaredConstructor.newInstance();
        flag.set(lazyMan1, false);
        LazyMan lazyMan2 = declaredConstructor.newInstance();
        System.out.println(lazyMan1);
        System.out.println(lazyMan2);
    }
}

為什么要使用 volatile 關(guān)鍵字呢

不是原子性操作

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

2.執(zhí)行構(gòu)造方法

3.把對(duì)象指向這個(gè)空間

指令重排可能會(huì)發(fā)生 加上volatile關(guān)閉指令重排

內(nèi)部類(lèi)懶漢式

package com.wanshi.single;

public class Holder {

    private Holder() {

    }

    public static class InnerClass {
        private static final Holder HOLDER = new Holder();
    }
}

案例全部通過(guò)測(cè)試!

小結(jié)

單例模式共有5種創(chuàng)建方式,分別為餓漢式、DCL懶漢式、雙檢鎖懶漢式、Enum枚舉餓漢式,內(nèi)部類(lèi)懶漢式,這幾種方式要掌握,項(xiàng)目中對(duì)于全局唯一的對(duì)象將其封裝為單例模式,開(kāi)箱即用,非常方便,以及面試中,會(huì)讓手寫(xiě)單例模式,可謂是大廠必備!

以上就是詳解Java單例模式的實(shí)現(xiàn)與原理剖析的詳細(xì)內(nèi)容,更多關(guān)于Java單例模式的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • springboot+jwt+springSecurity微信小程序授權(quán)登錄問(wèn)題

    springboot+jwt+springSecurity微信小程序授權(quán)登錄問(wèn)題

    這篇文章主要介紹了springboot+jwt+springSecurity微信小程序授權(quán)登錄問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-01-01
  • 淺談Spring Cloud Eureka 自我保護(hù)機(jī)制

    淺談Spring Cloud Eureka 自我保護(hù)機(jī)制

    這篇文章主要介紹了淺談Spring Cloud Eureka 自我保護(hù)機(jī)制,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-06-06
  • Spring基于XML實(shí)現(xiàn)Aop

    Spring基于XML實(shí)現(xiàn)Aop

    這篇文章主要介紹了Spring中基于xml的AOP的詳細(xì)步驟,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-07-07
  • JDK動(dòng)態(tài)代理提高代碼可維護(hù)性和復(fù)用性利器

    JDK動(dòng)態(tài)代理提高代碼可維護(hù)性和復(fù)用性利器

    這篇文章主要為大家介紹了JDK動(dòng)態(tài)代理提高代碼可維護(hù)性和復(fù)用性利器,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-10-10
  • Idea中maven無(wú)法下載依賴包問(wèn)題解決

    Idea中maven無(wú)法下載依賴包問(wèn)題解決

    用過(guò)idea開(kāi)發(fā)過(guò)項(xiàng)目的同學(xué),偶爾會(huì)遇到項(xiàng)目中有一些依賴沒(méi)法下載,或者依賴包已經(jīng)有項(xiàng)目卻無(wú)法掃到的問(wèn)題,本文就詳細(xì)的介紹了解決方法,感興趣的可以了解一下
    2020-08-08
  • JAVA如何調(diào)用wsdl過(guò)程詳解

    JAVA如何調(diào)用wsdl過(guò)程詳解

    這篇文章主要介紹了JAVA如何調(diào)用wsdl過(guò)程詳解,文中介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-07-07
  • java面試散列表及樹(shù)所對(duì)應(yīng)容器類(lèi)及HashMap沖突解決全面分析

    java面試散列表及樹(shù)所對(duì)應(yīng)容器類(lèi)及HashMap沖突解決全面分析

    這篇文章主要介紹了java面試中的java散列表及樹(shù)所對(duì)應(yīng)容器類(lèi)與HashMap沖突解決的問(wèn)題總結(jié),有需要的朋友可以借鑒參考下,希望能夠有所幫助
    2021-10-10
  • 分布式框架Zookeeper?api的使用介紹

    分布式框架Zookeeper?api的使用介紹

    Zookeeper作為?個(gè)分布式框架,主要用來(lái)解決分布式?致性問(wèn)題,它提供了簡(jiǎn)單的分布式原語(yǔ),并且對(duì)多種編程語(yǔ)?提供了API,所以接下來(lái)重點(diǎn)來(lái)看下Zookeeper的java客戶端API使用方式
    2022-09-09
  • Java線程關(guān)閉的3種方法

    Java線程關(guān)閉的3種方法

    這篇文章介紹了Java線程關(guān)閉的3種方法,有需要的朋友可以參考一下
    2013-10-10
  • java睡眠排序算法示例實(shí)現(xiàn)

    java睡眠排序算法示例實(shí)現(xiàn)

    這篇文章主要為大家介紹了java睡眠排序算法的示例實(shí)現(xiàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步
    2022-02-02

最新評(píng)論