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

Java中的各種單例模式優(yōu)缺點(diǎn)解析

 更新時(shí)間:2023年07月06日 08:47:22   作者:索碼理  
這篇文章主要介紹了Java中的各種單例模式解析,單例模式是Java中最簡(jiǎn)單的設(shè)計(jì)模式之一,這種類型的設(shè)計(jì)模式屬于創(chuàng)建者模式,它提供了一種訪問(wèn)對(duì)象的最佳方式,需要的朋友可以參考下

單例模式

單例模式是一種創(chuàng)建型設(shè)計(jì)模式,其目的是確保類只有一個(gè)實(shí)例,并且提供全局訪問(wèn)點(diǎn)以訪問(wèn)該實(shí)例。

在 Java 中,實(shí)現(xiàn)單例模式有多種方式,下面介紹其中的一些。

餓漢式單例模式

在餓漢式單例模式中,實(shí)例在類加載時(shí)就被創(chuàng)建,因此可以保證實(shí)例的唯一性。該模式的實(shí)現(xiàn)非常簡(jiǎn)單,可以使用靜態(tài)初始化器或者私有構(gòu)造方法來(lái)實(shí)現(xiàn)。例如:

public class Singleton {
    private static final Singleton INSTANCE = new Singleton();
    private Singleton() {}
    public static Singleton getInstance() {
        return INSTANCE;
    }
}

在這個(gè)例子中, INSTANCE 是一個(gè)靜態(tài)常量,它在類加載時(shí)被初始化為 Singleton 類的實(shí)例。getInstance() 方法提供了對(duì)該實(shí)例的全局訪問(wèn)點(diǎn)。

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

  • 線程安全,因?yàn)閷?shí)例在類加載的時(shí)候就已經(jīng)創(chuàng)建好了。
  • 簡(jiǎn)單易用,沒(méi)有線程同步等復(fù)雜問(wèn)題。
  • 線程訪問(wèn)單例實(shí)例的速度比懶漢式單例模式更快。

缺點(diǎn):

  • 類加載時(shí)就創(chuàng)建實(shí)例,有可能會(huì)浪費(fèi)資源。
  • 如果單例類依賴于其他類,這些依賴的類在類加載時(shí)也會(huì)被創(chuàng)建,

懶漢式單例模式

在懶漢式單例模式中,實(shí)例在第一次使用時(shí)才被創(chuàng)建。

public class Singleton {
    private static Singleton instance;
    private Singleton() {}
    public static Singleton getInstance(){
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

在上面的實(shí)現(xiàn)中,instance 是靜態(tài)變量,用于存儲(chǔ)單例對(duì)象。在 getInstance 方法中,如果 instance 為 null,則創(chuàng)建一個(gè)新的 Singleton 對(duì)象,否則直接返回 instance。由于沒(méi)有進(jìn)行同步鎖定,所以線程不安全,可能會(huì)導(dǎo)致并發(fā)創(chuàng)建多個(gè)實(shí)例的問(wèn)題。

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

  • 延遲對(duì)象的創(chuàng)建時(shí)間,減少內(nèi)存占用。
  • 簡(jiǎn)單易懂,易于實(shí)現(xiàn)。

缺點(diǎn):

  • 非線程安全,需要考慮并發(fā)情況。
  • 多線程環(huán)境下,需要使用同步鎖或者雙重校驗(yàn)鎖來(lái)保證線程安全,可能會(huì)影響性能。

雙重校驗(yàn)鎖單例模式

“雙重檢查鎖”(Double-Checked Locking) 是懶漢式的一種優(yōu)化,這種實(shí)現(xiàn)方式結(jié)合了懶漢式和餓漢式的優(yōu)點(diǎn),既能夠延遲對(duì)象的創(chuàng)建時(shí)間,又能夠保證線程安全。

public class Singleton {
    private static volatile Singleton INSTANCE;
    private Singleton() {}
    public static Singleton getInstance() {
        if (INSTANCE == null) {
            synchronized (Singleton.class) {
                if (INSTANCE == null) {
                    INSTANCE = new Singleton();
                }
            }
        }
        return INSTANCE;
    }
}

在這個(gè)例子中, INSTANCE 是一個(gè) volatile 的靜態(tài)變量,它在第一次使用時(shí)被創(chuàng)建。getInstance() 方法使用雙重檢查鎖定來(lái)確保 INSTANCE 的唯一性。當(dāng)多個(gè)線程同時(shí)訪問(wèn) getInstance() 方法時(shí),只有第一個(gè)線程會(huì)獲得鎖定并創(chuàng)建實(shí)例。其他線程會(huì)等待鎖定被釋放后再次檢查 INSTANCE 是否為空,從而避免了多次創(chuàng)建實(shí)例的情況。

需要注意的是,使用 volatile 關(guān)鍵字可以確保 INSTANCE 變量的可見(jiàn)性和有序性,從而保證多線程環(huán)境下的正確性。

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

  • 延遲加載,只有當(dāng)需要用到實(shí)例時(shí)才會(huì)創(chuàng)建,節(jié)省了系統(tǒng)資源。
  • 線程安全,適合高并發(fā)場(chǎng)景。

缺點(diǎn):

  • 實(shí)現(xiàn)復(fù)雜,容易出現(xiàn)問(wèn)題。
  • 由于 Java 內(nèi)存模型的限制,可能會(huì)出現(xiàn)指令重排的問(wèn)題,需要使用 volatile 關(guān)鍵字來(lái)解決。

枚舉單例模式

枚舉單例模式是一種比較新的單例模式實(shí)現(xiàn)方式,它在 Java 5 中引入。它利用了 Java 中枚舉類型的特性來(lái)實(shí)現(xiàn)單例模式,枚舉類型的每個(gè)枚舉常量都是單例的。

public enum Singleton {
    INSTANCE;
    public void doSomething() {
        // do something...
    }
}

在這個(gè)例子中,枚舉類型 Singleton 只有一個(gè)枚舉常量 INSTANCE ,該常量在枚舉類型初始化時(shí)被創(chuàng)建。由于枚舉類型的實(shí)例在 Java 虛擬機(jī)中是唯一的,因此枚舉常量也是單例的。我們可以通過(guò) Singleton.INSTANCE 來(lái)訪問(wèn)該實(shí)例,并調(diào)用 doSomething() 方法。

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

  • 簡(jiǎn)單明了: 枚舉單例模式的實(shí)現(xiàn)非常簡(jiǎn)單,而且可以保證線程安全和實(shí)例的唯一性。
  • 序列化安全: 由于枚舉實(shí)例在 JVM 中是唯一的,因此可以保證序列化和反序列化的安全性。
  • 防止反射攻擊: 枚舉實(shí)例在 JVM 中是唯一的,因此可以避免反射攻擊。

缺點(diǎn):

  • 不支持延遲加載 ,因?yàn)槊杜e類型的實(shí)例在類加載時(shí)就已經(jīng)被創(chuàng)建了。
  • 不能繼承其他類 ,因?yàn)槊杜e類型默認(rèn)繼承了Enum類。

靜態(tài)內(nèi)部類單例模式

靜態(tài)內(nèi)部類單例模式是一種優(yōu)雅而簡(jiǎn)潔的實(shí)現(xiàn)方式。它利用了 Java 類加載器的機(jī)制來(lái)保證實(shí)例的唯一性,并避免了餓漢式單例模式的缺點(diǎn)。

public class Singleton {
    private Singleton() {}
    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }
    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

在這個(gè)例子中, Singleton 類的構(gòu)造方法是私有的,只能在 Singleton 類的內(nèi)部進(jìn)行調(diào)用。 SingletonHolder 類是 Singleton 類的一個(gè)靜態(tài)內(nèi)部類,它在 Singleton 類被加載時(shí)并不會(huì)立即被加載,而是在第一次調(diào)用 Singleton.getInstance() 方法時(shí)才會(huì)被加載,從而實(shí)現(xiàn)了延遲加載。

由于靜態(tài)內(nèi)部類 SingletonHolder 只會(huì)被加載一次,因此 INSTANCE 實(shí)例也只會(huì)被創(chuàng)建一次,從而保證了實(shí)例的唯一性。總的來(lái)說(shuō),靜態(tài)內(nèi)部類單例模式是一種比較優(yōu)秀的單例模式實(shí)現(xiàn)方式,它兼顧了線程安全、懶加載和高效等特點(diǎn),是一種值得推薦的單例模式實(shí)現(xiàn)方式。

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

  • 線程安全: 靜態(tài)內(nèi)部類只會(huì)被加載一次,因此可以保證單例對(duì)象的線程安全性;
  • 懶加載:靜態(tài)內(nèi)部類只有在被調(diào)用時(shí)才會(huì)被加載,從而實(shí)現(xiàn)了懶加載的效果;
  • 高效:靜態(tài)內(nèi)部類單例模式?jīng)]有加鎖,所以性能比懶漢式和餓漢式都要高;
  • 簡(jiǎn)單: 靜態(tài)內(nèi)部類單例模式的實(shí)現(xiàn)比較簡(jiǎn)單,代碼量較少。

缺點(diǎn):

  • 不易理解: 相比于餓漢式和懶漢式,靜態(tài)內(nèi)部類單例模式的實(shí)現(xiàn)方式可能不太容易理解;
  • 無(wú)法傳遞參數(shù): 靜態(tài)內(nèi)部類單例模式的構(gòu)造函數(shù)是私有的,無(wú)法傳遞參數(shù)。如果需要傳遞參數(shù),需要使用其他方式實(shí)現(xiàn)。

注冊(cè)式單例模式

注冊(cè)式單例模式是一種靈活而可擴(kuò)展的實(shí)現(xiàn)方式。在該模式中,單例實(shí)例被注冊(cè)到一個(gè)全局的注冊(cè)表中,可以實(shí)現(xiàn)對(duì)象的統(tǒng)一管理和獲取,但需要注意容器的生命周期和線程安全問(wèn)題。

下面是一個(gè)使用 ConcurrentHashMap 實(shí)現(xiàn)注冊(cè)式單例模式的例子:

public class Singleton {
    private static Map<String, Singleton> instances = new ConcurrentHashMap<>();
    static {
        instances.put(Singleton.class.getName(), new Singleton());
    }
    private Singleton() {}
    public static Singleton getInstance() {
        return instances.get(Singleton.class.getName());
    }
    public static void register(String key, Singleton instance) {
        instances.put(key, instance);
    }
    public static Singleton getRegisteredInstance(String key) {
        return instances.get(key);
    }
}

Spring 框架中的 Bean 注冊(cè)機(jī)制使用的是注冊(cè)式單例模式。在 Spring 中, Bean 的注冊(cè)是通過(guò) BeanDefinitionRegistry 接口來(lái)完成的,而 BeanDefinitionRegistry 接口的實(shí)現(xiàn)類包括了 DefaultListableBeanFactoryGenericApplicationContext 等。這些實(shí)現(xiàn)類在內(nèi)部都使用了類似于注冊(cè)式單例模式的方式來(lái)注冊(cè)和管理 Bean 。

具體來(lái)說(shuō), Spring 在注冊(cè) Bean 時(shí),會(huì)將 Bean 的定義信息封裝成一個(gè) BeanDefinition 對(duì)象,并將其注冊(cè)到一個(gè)全局的 BeanFactory 中,以供后續(xù)的使用。在注冊(cè) Bean 的過(guò)程中, Spring 會(huì)根據(jù) BeanDefinition 中的配置信息來(lái)創(chuàng)建相應(yīng)的 Bean 實(shí)例,同時(shí)還會(huì)對(duì)其進(jìn)行依賴注入、生命周期管理等操作。

需要注意的是,SpringBean 注冊(cè)機(jī)制中,雖然使用了類似于注冊(cè)式單例模式的方式來(lái)管理 Bean ,但它并不是一個(gè)完全的單例模式實(shí)現(xiàn)。在 Spring 中, Bean 的單例性是在運(yùn)行時(shí)動(dòng)態(tài)實(shí)現(xiàn)的,而不是在編譯期就確定的。也就是說(shuō),如果在 BeanDefinition 中將 scope 屬性設(shè)置為 prototype ,那么每次獲取該 Bean 實(shí)例時(shí)都會(huì)創(chuàng)建一個(gè)新的對(duì)象,而不是返回同一個(gè)單例實(shí)例。

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

  • 可以管理多個(gè)單例實(shí)例,可以通過(guò)名稱或者其他方式來(lái)獲取實(shí)例。
  • 避免了全局變量帶來(lái)的問(wèn)題,比如命名沖突、不同作用域訪問(wèn)困難等。

缺點(diǎn):

  • 容易造成內(nèi)存泄漏,因?yàn)閱卫龑?shí)例不會(huì)被釋放。
  • 可能會(huì)造成重復(fù)創(chuàng)建對(duì)象的問(wèn)題。

ThreadLocal單例模式

ThreadLocal單例模式這種實(shí)現(xiàn)方式將單例對(duì)象存儲(chǔ)在ThreadLocal中,每個(gè)線程都有自己的單例對(duì)象副本,保證了線程安全。

public class Singleton {
    private static final ThreadLocal<Singleton> singletonThreadLocal = 
        new ThreadLocal<Singleton>() {
            @Override
            protected Singleton initialValue() {
                return new Singleton();
            }
        };
    private Singleton() {}
    public static Singleton getInstance() {
        return singletonThreadLocal.get();
    }
}

在這個(gè)示例中,每個(gè)線程都有自己的 Singleton 對(duì)象副本,使用 ThreadLocal 可以避免線程安全問(wèn)題。

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

  • 每個(gè)線程都有自己的單例對(duì)象副本,線程安全。
  • 可以避免鎖競(jìng)爭(zhēng),提高性能。

缺點(diǎn):

  • 可能會(huì)導(dǎo)致內(nèi)存泄漏問(wèn)題,需要注意對(duì)象的生命周期。

CAS單例模式

CAS單例模式這種實(shí)現(xiàn)方式利用了CAS原子操作的特性,可以保證線程安全,但需要注意性能問(wèn)題。

public class Singleton {
    private static volatile Singleton instance;
    private Singleton() {}
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    Singleton temp = new Singleton();
                    if (compareAndSetInstance(null, temp)) {
                        instance = temp;
                    }
                }
            }
        }
        return instance;
    }
    private static boolean compareAndSetInstance(Singleton expect, Singleton update) {
        return Unsafe.getUnsafe().compareAndSwapObject(Singleton.class, 
            Unsafe.objectFieldOffset(Singleton.class, "instance"), expect, update);
    }
}

在這個(gè)示例中,使用了 volatileCAS 原子操作來(lái)保證線程安全,同時(shí)實(shí)現(xiàn)了懶加載。需要注意的是,使用 Unsafe 類需要特殊權(quán)限,并且 CAS 實(shí)現(xiàn)的復(fù)雜度比較高,適用于高并發(fā)場(chǎng)景。

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

  • 線程安全,高并發(fā)場(chǎng)景性能較好。

缺點(diǎn):

  • 實(shí)現(xiàn)復(fù)雜,需要理解 CAS 原子操作。
  • 需要使用 Unsafe 類,需要特殊權(quán)限。
  • 適用于高并發(fā)場(chǎng)景,對(duì)于低并發(fā)場(chǎng)景可能沒(méi)有明顯的性能優(yōu)勢(shì)。

總結(jié)

總之,單例模式是一種非常常用的設(shè)計(jì)模式,可以確保類只有一個(gè)實(shí)例,并提供全局訪問(wèn)點(diǎn)以訪問(wèn)該實(shí)例。在 Java 中,有多種方式可以實(shí)現(xiàn)單例模式,開(kāi)發(fā)者可以根據(jù)實(shí)際需要選擇適合自己的實(shí)現(xiàn)方式。

到此這篇關(guān)于Java中的各種單例模式優(yōu)缺點(diǎn)解析的文章就介紹到這了,更多相關(guān)Java單例模式解析內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論