国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Java設(shè)計模式之單例模式

這篇具有很好參考價值的文章主要介紹了Java設(shè)計模式之單例模式。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

定義與類型

定義:保證一個類僅有一個實例,并提供一個全局訪問點

類型:創(chuàng)建型

單例模式使用場景

想確保任何情況下都絕對只有一個實例

例如:線程池,數(shù)據(jù)庫連接池一般都為單例模式

單例模式優(yōu)點

  • 在內(nèi)存中只有一個實例,減少內(nèi)存開銷
  • 可以避免對資源的多重占用
  • 設(shè)置全局訪問點,嚴格控制訪問

缺點

沒有接口,擴展困難

單例模式-重點

  • 私有構(gòu)造器
  • 線程安全(重點)
  • 延遲加載(重點)
  • 序列化和反序列化安全(序列化和反序列化會破壞單例模式)
  • 反射(防止反射攻擊)

實現(xiàn)單例模式-懶漢式

/**
 * 懶漢式
 */
public class LazySingleton {
    private static LazySingleton lazySingleton = null;
    private LazySingleton(){

    }
    public static LazySingleton getInstance(){
        if (lazySingleton == null){
            lazySingleton = new LazySingleton();
        }
        return lazySingleton;
    }
}

將構(gòu)造器私有化,提供一個靜態(tài)類來獲取對象實例

但是該方法是線程不安全的,如果在LazySingleton未實例化前,多個線程同時調(diào)用,例如線程1判斷l(xiāng)azySingleton為null,進入下一步并沒有創(chuàng)建對象時,另一個對象也判斷l(xiāng)azySingleton為空這時就會出現(xiàn)創(chuàng)造出多個實例的錯誤。

使用多線程debug方式顯示問題

在idea中想要使用多線程debug方式需要按如圖所示修改,將斷點改為Thread級別

java單例模式,單例模式,java,設(shè)計模式

在Test的main方法中開辟兩個線程

public class Test {
    public static void main(String[] args) {
//        LazySingleton instance = LazySingleton.getInstance();
        Thread t1 = new Thread(new T());
        Thread t2 = new Thread(new T());
        t1.start();
        t2.start();
        System.out.println("main end");
    }
}

T為Runnable的實現(xiàn)類

/**
 * 設(shè)置線程,開啟其他線程獲取LazySingleton實例
 */
public class T implements Runnable{
    @Override
    public void run() {
        LazySingleton instance = LazySingleton.getInstance();
        System.out.println(Thread.currentThread().getName()+"  "+instance);
    }
}

使用debug方式啟動Test的main方法,此時在Frames中就可以看到除main線程外,還有兩個運行中的Thread

java單例模式,單例模式,java,設(shè)計模式

切換到Thread-0線程,走到if判斷后,且未創(chuàng)建LazySingleton實例時刻

java單例模式,單例模式,java,設(shè)計模式

?切換到Thread-1線程,使Thread-1線程繼續(xù)運行直到Thread-1線程結(jié)束

然后切回Thread-0線程,使Thread-0線程繼續(xù)運行直到Thread-0線程結(jié)束

觀看控制臺即可發(fā)現(xiàn)在堆中創(chuàng)建了兩個?LazySingleton實例

java單例模式,單例模式,java,設(shè)計模式

解決方式

?1、在獲取LazySingleton實例方法上加上synchronized關(guān)鍵字java單例模式,單例模式,java,設(shè)計模式由于getInstance是靜態(tài)方法,所有給該方法上加入synchronized關(guān)鍵字等同于給整個LazySingleton類加鎖,雖然能解決并發(fā)情況下創(chuàng)建多個實例的問題,但是會影響性能。

DoubleCheck雙重檢查

?通過雙重檢查既能解決并發(fā)情況下創(chuàng)建多個實例的問題,也可以很好的提升性能

雙重檢查代碼實現(xiàn)

第一版雙重檢查代碼實現(xiàn)

java單例模式,單例模式,java,設(shè)計模式

在第一次判斷后加上synchronized關(guān)鍵字再判斷一次,這樣既可以解決并發(fā)情況下創(chuàng)建多個實例的問題,對性能的影響也非常有限

但是這種做法也會產(chǎn)生問題因為創(chuàng)建對象的過程并不是原子操作,在jvm內(nèi)部可能會使創(chuàng)建過程發(fā)生指令重排序

java單例模式,單例模式,java,設(shè)計模式

一般創(chuàng)建過程

  1. 分配內(nèi)存給這個對象
  2. 初始化對象
  3. 設(shè)置lazyDoubleCheckSingleton 指向分配的內(nèi)存地址

jvm會在什么情況下發(fā)生指令重排序呢?

jvm允許在單線程不影響最終結(jié)果的情況下發(fā)生指令重排序

在該實例中第二步和第三步發(fā)生重排序,即先指向內(nèi)存地址在初始化對象并不會改變單線程中的最終結(jié)果,所有jvm會允許這兩步發(fā)生重排序

發(fā)生指令重拍尋后的創(chuàng)建過程

  1. 分配內(nèi)存給這個對象
  2. 設(shè)置lazyDoubleCheckSingleton 指向分配的內(nèi)存地址
  3. 初始化對象

但在并發(fā)的情況下就有可能出現(xiàn)線程1發(fā)生指令重排 剛指向完內(nèi)存地址時,?

線程2進入第一層判斷發(fā)現(xiàn)lazyDoubleCheckSingleton并不為空,然后直接返回

這時就有可能出現(xiàn)別的線程返回的是沒有初始化完成的對象從而發(fā)生一些意想不到的錯誤

解決指令重排序

1.禁用指令重排序

想要禁用指令重排序非常簡單只需將私有的成員變量 lazyDoubleCheckSingleton 增加?volatile關(guān)鍵字即可

java單例模式,單例模式,java,設(shè)計模式

2.線程1的指令重排對線程2是不可見的

想要線程1 的指令重排對線程2 不可見 需要應用靜態(tài)內(nèi)部類

/**
 *  想要線程1 的指令重排對線程2 不可見 需要應用靜態(tài)內(nèi)部類
 */
public class StaticInnerClassSingleton {
    private StaticInnerClassSingleton(){

    }

    private static class Inner{
        private static StaticInnerClassSingleton staticInnerClassSingleton = new StaticInnerClassSingleton();
    }

    public static StaticInnerClassSingleton getInstance(){
        return Inner.staticInnerClassSingleton;
    }
}

原理

在介紹原理前首先介紹下靜態(tài)內(nèi)部類的加載時機

  1. 外部類初次加載,會初始化靜態(tài)變量、靜態(tài)代碼塊、靜態(tài)方法,但不會加載內(nèi)部類和靜態(tài)內(nèi)部類。
  2. 實例化外部類,調(diào)用外部類的靜態(tài)方法、靜態(tài)變量,則外部類必須先進行加載,但只加載一次。
  3. 直接調(diào)用靜態(tài)內(nèi)部類時,外部類不會加載。

即?靜態(tài)內(nèi)部類不會自動初始化,只有調(diào)用靜態(tài)內(nèi)部類的方法,靜態(tài)域,或者構(gòu)造方法的時候才會加載靜態(tài)內(nèi)部類。

在了解靜態(tài)內(nèi)部類的加載時機后,再來解釋利用靜態(tài)內(nèi)部類是如何實現(xiàn)隔離線程間的指令重排的

jvm在類初始化階段會給class對象加鎖,在多個線程同時初始化該類時 會使多個線程初始化處于同步階段,所以在靜態(tài)內(nèi)部類初始化階段可以做到對其他線程的隔離。

java單例模式,單例模式,java,設(shè)計模式

?基于該特性可以設(shè)計出一個通過靜態(tài)內(nèi)部類的基于類初始化的延遲加載(懶加載)解決方案

實現(xiàn)單例模式-餓漢式

餓漢式是在類加載階段就進行實例化,餓漢式創(chuàng)造簡單,也能解決并發(fā)情況下創(chuàng)建多實例的問題

/**
 * 餓漢式
 */
public class HungrySingleton {
    private static HungrySingleton hungrySingleton;
    
    private HungrySingleton(){
        
    }
    
    static {
        // 基于靜態(tài)代碼塊的餓漢式單例模式
        hungrySingleton = new HungrySingleton();
    }
    
    public HungrySingleton getInstance(){
        return hungrySingleton;
    }
    
}

餓漢式雖然簡單易用但是由于在類加載階段就會創(chuàng)建實例,如果大量使用這種方式會導致內(nèi)存占用過大問題

單例模式-序列化和反序列化安全

以餓漢式為例,將實例對象輸出到磁盤

代碼示例?

public class Test {
    public static void main(String[] args) throws IOException, ClassNotFoundException {

        HungrySingleton instance = HungrySingleton.getInstance();
        ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("singleton_file"));
        outputStream.writeObject(instance);

        ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("singleton_file"));
        HungrySingleton object = (HungrySingleton)inputStream.readObject();


        System.out.println("instance: "+instance);
        System.out.println("object: "+object);

    }
}

要想將實例對象輸出到磁盤上需要讓實例類實現(xiàn) Serializable接口使其可序列化

java單例模式,單例模式,java,設(shè)計模式

題外話 serialVersionUID版本號的作用

當對同一個實體序列化反序列化時,需要serialVersionUID值一致才能成功。如果我們不顯示指定serialVersionUID,在序列化時會自動生成一個serialVersionUID。當實體類改動了,反序列化時,會生成一個新serialVersionUID。這兩個serialVersionUID的值肯定不一致,從而反序列化會失敗。但是如果顯示指定,就不會生成新serialVersionUID值了。反序列化的serialVersionUID就是原序列化的serialVersionUID。

運行Test的main方法,查看打印結(jié)果

java單例模式,單例模式,java,設(shè)計模式

?可以看到在經(jīng)過序列化后獲取的對象實例并不是同一個對象了,這就破壞了單例模式。

如何解決?

先說結(jié)論,在單例類上加上readResolve方法就可以實現(xiàn)序列化后的對象也是同一個對象


    private Object readResolve(){
        return hungrySingleton;
    }

加上該方法后重新執(zhí)行main方法,查看打印結(jié)果

java單例模式,單例模式,java,設(shè)計模式

?發(fā)現(xiàn)確實已經(jīng)是同一個對象了

為什么需要加一個readResolve方法呢?

讓我們來看下ObjectInputStream的源碼

首先ObjectInputStream的readObject方法調(diào)用了readObject0

java單例模式,單例模式,java,設(shè)計模式

?進入readObject0方法,發(fā)現(xiàn)內(nèi)部有一個switch case判斷,我們是序列化的對象實例,所有直接看case TC_OBJECT 這一部分

java單例模式,單例模式,java,設(shè)計模式

發(fā)現(xiàn)他的checkResolve方法調(diào)用的readOrdinaryObject方法,繼續(xù)進入該方法

    /**
     * Reads and returns "ordinary" (i.e., not a String, Class,
     * ObjectStreamClass, array, or enum constant) object, or null if object's
     * class is unresolvable (in which case a ClassNotFoundException will be
     * associated with object's handle).  Sets passHandle to object's assigned
     * handle.
     */
    private Object readOrdinaryObject(boolean unshared)
        throws IOException
    {
        if (bin.readByte() != TC_OBJECT) {
            throw new InternalError();
        }

        ObjectStreamClass desc = readClassDesc(false);
        desc.checkDeserialize();

        Class<?> cl = desc.forClass();
        if (cl == String.class || cl == Class.class
                || cl == ObjectStreamClass.class) {
            throw new InvalidClassException("invalid class descriptor");
        }

        Object obj;
        try {
            obj = desc.isInstantiable() ? desc.newInstance() : null;
        } catch (Exception ex) {
            throw (IOException) new InvalidClassException(
                desc.forClass().getName(),
                "unable to create instance").initCause(ex);
        }

        passHandle = handles.assign(unshared ? unsharedMarker : obj);
        ClassNotFoundException resolveEx = desc.getResolveException();
        if (resolveEx != null) {
            handles.markException(passHandle, resolveEx);
        }

        if (desc.isExternalizable()) {
            readExternalData((Externalizable) obj, desc);
        } else {
            readSerialData(obj, desc);
        }

        handles.finish(passHandle);

        if (obj != null &&
            handles.lookupException(passHandle) == null &&
            desc.hasReadResolveMethod())
        {
            Object rep = desc.invokeReadResolve(obj);
            if (unshared && rep.getClass().isArray()) {
                rep = cloneArray(rep);
            }
            if (rep != obj) {
                // Filter the replacement object
                if (rep != null) {
                    if (rep.getClass().isArray()) {
                        filterCheck(rep.getClass(), Array.getLength(rep));
                    } else {
                        filterCheck(rep.getClass(), -1);
                    }
                }
                handles.setObject(passHandle, obj = rep);
            }
        }

        return obj;
    }

原來readOrdinaryObject首先會通過一個三目運算來創(chuàng)建序列化的對象。如果這個對象能實例化就創(chuàng)建一個新的對象。

obj = desc.isInstantiable() ? desc.newInstance() : null;

那為什么在單例類中加入一個readResolve方法就能改變這種情況呢?

繼續(xù)往下看,在第2076行有個判斷,從名字上就能看得出是用來判斷是否能獲取到readResolve方法的

java單例模式,單例模式,java,設(shè)計模式

?進入readResolve方法查看

java單例模式,單例模式,java,設(shè)計模式

?在這里可以看到如果沒有readResolveMethod不為空那么就會返回true。

走到在就終于明白原因了,太不容易了

原來是readOrdinaryObject會查看實例類內(nèi)部是否有readResolve方法,如果存在readResolve方法

那么就會通過反射的方式獲取readResolve中的返回值,將obj的引用改為readResolve方法的返回

java單例模式,單例模式,java,設(shè)計模式

從而最終改變了反序列化的引用地址,使其的引用變?yōu)閱卫膭?chuàng)建的實例。

總結(jié),反序列化時會創(chuàng)建了一個新的實例對象,如果在單例對象代碼中添加public Object readResolve()方法,會在最后改變了這個實例對象的引用為單例對象readResolve()方法的返回結(jié)果。

通過枚舉類實現(xiàn)單例模式

Google 首席 Java 架構(gòu)師、《Effective Java》一書作者、Java集合框架的開創(chuàng)者Joshua Bloch在Effective Java一書中提到:

單元素的枚舉類型已經(jīng)成為實現(xiàn)Singleton的最佳方法?!敬罄姓媸沁@么說的】

那么枚舉類型有什么神奇之處呢?

特點

  • 枚舉類型可以解決序列化問題
  • 枚舉類型可以解決反射功能的問題

創(chuàng)建一個枚舉類型

public enum EnumInstance {
    INSTANCE;
    private Object data;
    private String name;

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

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

序列化枚舉類實例

java單例模式,單例模式,java,設(shè)計模式

查看打印結(jié)果

java單例模式,單例模式,java,設(shè)計模式

?發(fā)現(xiàn)枚舉類的序列化結(jié)果是一致的

同樣的來看一下readEnum方法的具體邏輯

java單例模式,單例模式,java,設(shè)計模式

?核心邏輯是通過cl(類型),和name獲取枚舉常量,由于枚舉name是唯一的并且對應一個枚舉常量,所有最終拿到的是同一個枚舉常量,沒有重新創(chuàng)建對象。因此序列化對單例模式的破壞對于枚舉類型是不起作用的。

枚舉是如何實現(xiàn)單例模式的呢?

通過jad 反編譯工具來看下答案

jad的官網(wǎng)為

JAD Java Decompiler Download Mirrorhttps://varaneckas.com/jad/下載jad,并解壓

配置環(huán)境變量 在系統(tǒng)變量中創(chuàng)建JAD_HOME變量,將jad目錄配置進去

java單例模式,單例模式,java,設(shè)計模式

?然后配置系統(tǒng)變量里的path變量

java單例模式,單例模式,java,設(shè)計模式

這樣就配置成功了。

找到EnumInstance的class文件執(zhí)行jad EnumInstance.class命令

java單例模式,單例模式,java,設(shè)計模式

?可以看到生成了一個EnumInstance.jad文件,這樣就使用jad生成了 EnumInstance.class的反編譯文件,看一下反編譯后的文件

首先可以發(fā)現(xiàn)枚舉類居然是被final修飾的?

public final class EnumInstance extends Enum

?再往下看發(fā)現(xiàn) 雖然沒有寫構(gòu)造方法,但是內(nèi)部卻已經(jīng)被創(chuàng)建出來一個私有的構(gòu)造器

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

再然后就是定義的getInstance方法和一個被final修飾的靜態(tài)成員變量INSTANCE;

    public static EnumInstance getInstance()
    {
        return INSTANCE;
    }
    public static final EnumInstance INSTANCE;

最后可以看到一個靜態(tài)代碼塊用來對成員變量INSTANCE初始化

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

從枚舉類的反編譯文件可以看出,枚舉類是一個餓漢式的單例模式,在類被加載時初始化,沒有延遲加載。

單例模式之線程單例

變量值的共享可以使用public?static的形式,所有線程都使用同一個變量,如果想實現(xiàn)每一個線程都有自己的共享變量該如何實現(xiàn)呢?JDK中的ThreadLocal類正是為了解決這樣的問題。

ThreadLocal類并不是用來解決多線程環(huán)境下的共享變量問題,而是用來提供線程內(nèi)部的共享變量,在多線程環(huán)境下,可以保證各個線程之間的變量互相隔離、相互獨立。在線程中,可以通過get()/set()方法來訪問變量。

ThreadLocal實例通常來說都是private static類型的,它們希望將狀態(tài)與線程進行關(guān)聯(lián)。這種變量在線程的生命周期內(nèi)起作用,可以減少同一個線程內(nèi)多個函數(shù)或者組件之間一些公共變量的傳遞的復雜度。

ThreadLocal主要api介紹

get()方法:獲取與當前線程關(guān)聯(lián)的ThreadLocal值。

set(T value)方法:設(shè)置與當前線程關(guān)聯(lián)的ThreadLocal值。

initialValue()方法:設(shè)置與當前線程關(guān)聯(lián)的ThreadLocal初始值。

remove()方法:將與當前線程關(guān)聯(lián)的ThreadLocal值刪除。

當調(diào)用get()方法的時候,若是與當前線程關(guān)聯(lián)的ThreadLocal值已經(jīng)被設(shè)置過,則不會調(diào)用initialValue()方法;否則,會調(diào)用initialValue()方法來進行初始值的設(shè)置。

通常initialValue()方法只會被調(diào)用一次,除非調(diào)用了remove()方法之后又調(diào)用get()方法,此時,與當前線程關(guān)聯(lián)的ThreadLocal值處于沒有設(shè)置過的狀態(tài)(其狀態(tài)體現(xiàn)在源碼中,就是線程的ThreadLocalMap對象是否為null),initialValue()方法仍會被調(diào)用。

initialValue()方法是protected類型的,很顯然是建議在子類重寫該函數(shù)的,所以通常該方法都會以匿名內(nèi)部類的形式被重寫,以指定初始值,例如:

創(chuàng)建一個ThreadLocalInstance

/**
 * ThreadLocal類可以實現(xiàn)線程之間的單例
 */
public class ThreadLocalInstance {
    private static ThreadLocal<ThreadLocalInstance>
            threadLocalInstanceThreadLocal = new ThreadLocal<ThreadLocalInstance>(){
        // 匿名內(nèi)部類重寫 initialValue方法
        @Override
        protected ThreadLocalInstance initialValue() {
//            return super.initialValue();
            return new ThreadLocalInstance();
        }
    };

    // 私有化構(gòu)造器
    private ThreadLocalInstance(){

    }

    public static ThreadLocalInstance getInstance(){
        return threadLocalInstanceThreadLocal.get();
    }
    
}

main線程中多次調(diào)用getInstance,在開辟新線程調(diào)用

        ThreadLocalInstance instance1 = ThreadLocalInstance.getInstance();
        ThreadLocalInstance instance2 = ThreadLocalInstance.getInstance();
        ThreadLocalInstance instance3 = ThreadLocalInstance.getInstance();
        ThreadLocalInstance instance4 = ThreadLocalInstance.getInstance();
        System.out.println(instance1);
        System.out.println(instance2);
        System.out.println(instance3);
        System.out.println(instance4);
        Thread t1 = new Thread(new T());
        Thread t2 = new Thread(new T());
        t1.start();
        t2.start();
        System.out.println("main end");

查看打印結(jié)果

java單例模式,單例模式,java,設(shè)計模式

可以發(fā)現(xiàn)ThreadLocalInstance會在每一個線程都創(chuàng)建一個實例,同一線程多次調(diào)用都是調(diào)用的該實例,這樣就實現(xiàn)了線程的單例

spring中的bean單例模式

Spring單例Bean與單例模式的區(qū)別在于他們關(guān)聯(lián)的環(huán)境不一樣,單例模式是指在一個jvm進程中僅有一個實例,而Spring單例是指一個Spring Bean容器(ApplicationContext)中僅有一個實例。

單例設(shè)計模式,在一個JVM進程中(理論上,一個運行的Java程序,就必定有自己獨立的JVM)僅有一個實例,于是無論在程序的何處獲取實例,始終都返回同一個對象,以Java內(nèi)置的Runtime為例(現(xiàn)在枚舉是單例模式的最佳實踐),無論何時獲取,下面的判斷始終為真:

//  基于懶漢模式實現(xiàn)
//  在一個JVM實例中始終只有一個實例
Runtime.getRuntime() == Runtime.getRuntime()

與此相比,Spring的單例Bean是與其容器(ApplicationContext)密切相關(guān)的,所以在一個JVM進程中,如果有多個Spring容器,即使是單例bean,也一定會創(chuàng)建多個實例,代碼示例如下:

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class,args);

        // 第一個spring bean容器
        AnnotationConfigApplicationContext context1 = new AnnotationConfigApplicationContext(Contextbean.class);
        User user1 = context1.getBean("user1", User.class);
        // 第二個spring bean容器
        AnnotationConfigApplicationContext context2 = new AnnotationConfigApplicationContext(Contextbean.class);
        User user2 = context2.getBean("user1", User.class);
        System.out.println("==========");
        // 這里絕對不會相等,因為創(chuàng)建了多個實例
        System.out.println(user1==user2);

    }

?java單例模式,單例模式,java,設(shè)計模式

打印結(jié)果和預想的一樣果然不是同一個對象實例

附:配置類和實體類

Spring的配置類

@Configuration
public class Contextbean {

    @Bean("user1")
    public User getUser(){
        return new User("zhangsan","18");
    }

}

User實體類

public class User {
    private String name;
    private String age;

    public User(String name, String age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }
}

?文章來源地址http://www.zghlxwxcb.cn/news/detail-783203.html

到了這里,關(guān)于Java設(shè)計模式之單例模式的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權(quán),不承擔相關(guān)法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務器費用

相關(guān)文章

  • Java課堂|獨一無二的事物(設(shè)計模式之單例模式)

    Java課堂|獨一無二的事物(設(shè)計模式之單例模式)

    本文主要講述 單例模式 ,文中使用通俗易懂的案例,使你更好的學習本章知識點并理解原理,做到有道無術(shù)。 單例模式是23種設(shè)計模式中 創(chuàng)建型模式 的一種,通過單例模式的方法創(chuàng)建的類在當前進程或者線程中只有一個實例。單例模式有兩種比較常見的實現(xiàn)方式: 餓漢式

    2024年02月07日
    瀏覽(24)
  • Java設(shè)計模式之單例模式詳解(懶漢式和餓漢式)

    在開發(fā)工作中,有些類只需要存在一個實例,這時就可以使用單例模式。Java中的單例模式是一種常見的設(shè)計模式,它確保一個類只有一個實例,并提供全局訪問點。下面來介紹一下兩種常見的單例模式:懶漢式和餓漢式。 懶漢式屬于一種延遲加載的單例模式,它的特點是在

    2024年02月15日
    瀏覽(25)
  • 設(shè)計模式之單例設(shè)計模式

    就是一個類只允許創(chuàng)建一個對象,那么我們稱該類為單例類,這種設(shè)計模式我們稱為單例模式。 資源共享:有些類擁有共享的資源,例如數(shù)據(jù)庫連接池、線程池、緩存等。使用單例模式確保只有一個實例,避免資源浪費和競爭條件。 線程安全:單例模式可以用來保證多線程

    2024年02月07日
    瀏覽(29)
  • 【前端設(shè)計模式】之單例模式

    在前端開發(fā)中,單例模式是一種常見的設(shè)計模式,用于確保一個類只有一個實例,并提供全局訪問點。在實現(xiàn)單例模式時,有一些最佳實踐和高級技巧可以幫助我們編寫更優(yōu)雅和可維護的代碼。 使用閉包是實現(xiàn)單例模式的一種常見方法。通過將類的實例保存在閉包中,并提供

    2024年02月09日
    瀏覽(25)
  • Unity設(shè)計模式之單例模式

    單例模式(Singleton)是設(shè)計模式中很常見的一種設(shè)計模式,目的是為了讓一個類在程序運行期間有且僅有一個實例,且方便全局訪問。 1、私有的構(gòu)造函數(shù)。 2、含有一個該類的靜態(tài)私有對象。 3、靜態(tài)的公有函數(shù)或?qū)傩?,方便用戶?chuàng)建或者獲取它本身的靜態(tài)私有對象。 當項目

    2023年04月09日
    瀏覽(23)
  • c++設(shè)計模式之單例模式

    一個類無論創(chuàng)建多少對象 , 都只能得到一個實例 如上述代碼中,我們通過new運算符創(chuàng)建出了類A的三個對象實例,而我們現(xiàn)在要做的是,如何設(shè)計類A,使得上述代碼運行之后永遠只產(chǎn)生同一個對象實例 ????????我們知道,一個類對象是通過這個類的構(gòu)造函數(shù)創(chuàng)建的,因此

    2024年01月19日
    瀏覽(26)
  • C#設(shè)計模式之單例模式

    單例模式(Singleton)保證一個類僅有一個實例,并提供一個訪問它的全局訪問點。 單例模式的結(jié)構(gòu)圖如下所示: 對一些類來說,只有一個實例是很重要的。如何才能保證一個類只有一個實例并且這個實例易于被訪問呢? 基于程序員之間的約定或是利用全局變量嗎? 雖然這樣

    2024年02月03日
    瀏覽(22)
  • 設(shè)計模式之單例模式(懶漢, 餓漢)

    設(shè)計模式之單例模式(懶漢, 餓漢)

    單例模式是一種常用的軟件設(shè)計模式, 該模式的主要目的是確保某一個類在內(nèi)存中只能有一個實例對象, 通過單例模式的方法創(chuàng)建的類在當前進程中只有一個實例對象. 常見的單例模式有兩種: 餓漢式, 這里的 “餓” 意義表述不夠清晰, 用 “急” 來表述意義更加容易聯(lián)想一些

    2024年02月22日
    瀏覽(20)
  • C#--設(shè)計模式之單例模式

    C#--設(shè)計模式之單例模式

    單例模式大概是所有設(shè)計模式中最簡單的一種,如果在面試時被問及熟悉哪些設(shè)計模式,你可能第一個答的就是單例模式。 單例模式的實現(xiàn)分為兩種: 餓漢式:在靜態(tài)構(gòu)造函數(shù)執(zhí)行時就立即實例化。 懶漢式:在程序執(zhí)行過程中第一次需要時再實例化。 兩者有各自適用的場景

    2024年02月14日
    瀏覽(12)
  • 淺談設(shè)計模式之單例模式

    淺談設(shè)計模式之單例模式

    單例模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對象的最佳方式。單例模式指的是 單一的一個類 ,該類負責創(chuàng)建自己的對象,并且保證該 對象唯一 。該類提供了一種訪問其唯一對象的方法,外部需要調(diào)用該類的對象可以通過方法獲取,不需要實例化類的對象。 關(guān)鍵點: 單例

    2024年02月16日
    瀏覽(20)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包