日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java单例模式与线程安全

發(fā)布時間:2023/12/10 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java单例模式与线程安全 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文章目錄

  • 1. 單例模式的定義
  • 2. 單例模式的設(shè)計(jì)要素
  • 3. 單例模式的6種實(shí)現(xiàn)及各實(shí)現(xiàn)的優(yōu)缺點(diǎn)
    • 3.1 懶漢式(線程不安全)
    • 3.2 餓漢式(線程安全)
    • 3.3 懶漢式(線程安全)
    • 3.4 雙重檢查鎖實(shí)現(xiàn)(線程安全)
    • 3.5 靜態(tài)內(nèi)部類實(shí)現(xiàn)(線程安全)
    • 3.6 枚舉類實(shí)現(xiàn)(線程安全)
  • 4. 單例模式的應(yīng)用場景

1. 單例模式的定義

? 定義: 確保一個類只有一個實(shí)例,并提供該實(shí)例的全局訪問點(diǎn)。這樣做的好處是:有些實(shí)例,全局只需要一個就夠了,使用單例模式就可以避免一個全局使用的類,頻繁的創(chuàng)建與銷毀,耗費(fèi)系統(tǒng)資源。

2. 單例模式的設(shè)計(jì)要素

  • 一個私有構(gòu)造函數(shù) (確保只能單例類自己創(chuàng)建實(shí)例)
  • 一個私有靜態(tài)變量 (確保只有一個實(shí)例)
  • 一個公有靜態(tài)函數(shù) (給使用者提供調(diào)用方法)

? 簡單來說就是,單例類的構(gòu)造方法不讓其他人修改和使用;并且單例類自己只創(chuàng)建一個實(shí)例,這個實(shí)例,其他人也無法修改和直接使用;然后單例類提供一個調(diào)用方法,想用這個實(shí)例,只能調(diào)用這個對外暴露的方法。這樣就確保了全局只創(chuàng)建了一次實(shí)例。

3. 單例模式的6種實(shí)現(xiàn)及各實(shí)現(xiàn)的優(yōu)缺點(diǎn)

3.1 懶漢式(線程不安全)

? 實(shí)現(xiàn):

public class Singleton {private static Singleton uniqueInstance;private Singleton() {}public static Singleton getUniqueInstance() {if (uniqueInstance == null) {uniqueInstance = new Singleton();}return uniqueInstance;} }

? 說明: 先不創(chuàng)建實(shí)例,當(dāng)?shù)谝淮伪徽{(diào)用時,再創(chuàng)建實(shí)例,所以被稱為懶漢式。

? 優(yōu)點(diǎn): 延遲了實(shí)例化,如果不需要使用該類,就不會被實(shí)例化,節(jié)約了系統(tǒng)資源。

? 缺點(diǎn): 線程不安全,多線程環(huán)境下,如果多個線程同時進(jìn)入了 if (uniqueInstance == null) ,若此時還未實(shí)例化,也就是uniqueInstance == null,那么就會有多個線程執(zhí)行 uniqueInstance = new Singleton(); 就會實(shí)例化多個實(shí)例。

3.2 餓漢式(線程安全)

? 實(shí)現(xiàn):

public class Singleton {private static Singleton uniqueInstance = new Singleton();private Singleton() {}public static Singleton getUniqueInstance() {return uniqueInstance;}}

? 說明: 先不管需不需要使用這個實(shí)例,直接先實(shí)例化好實(shí)例 (餓死鬼一樣,所以稱為餓漢式),然后當(dāng)需要使用的時候,直接調(diào)方法就可以使用了。

? 優(yōu)點(diǎn): 提前實(shí)例化好了一個實(shí)例,避免了線程不安全問題的出現(xiàn)。

? 缺點(diǎn): 直接實(shí)例化好了實(shí)例,不再延遲實(shí)例化;若系統(tǒng)沒有使用這個實(shí)例,或者系統(tǒng)運(yùn)行很久之后才需要使用這個實(shí)例,會造成操作系統(tǒng)的資源浪費(fèi)。

3.3 懶漢式(線程安全)

? 實(shí)現(xiàn):

public class Singleton {private static Singleton uniqueInstance;private static singleton() {}private static synchronized Singleton getUinqueInstance() {if (uniqueInstance == null) {uniqueInstance = new Singleton();}return uniqueInstance;}}

? 說明: 實(shí)現(xiàn)和 線程不安全的懶漢式 幾乎一樣,唯一不同的點(diǎn)是,在get方法上 加了一把鎖。如此一來,多個線程訪問,每次只有拿到鎖的的線程能夠進(jìn)入該方法,避免了多線程不安全問題的出現(xiàn)。

? 優(yōu)點(diǎn): 延遲實(shí)例化,節(jié)約了資源,并且是線程安全的。

? 缺點(diǎn): 雖然解決了線程安全問題,但是性能降低了。因?yàn)?#xff0c;即使實(shí)例已經(jīng)實(shí)例化了,既后續(xù)不會再出現(xiàn)線程安全問題了,但是鎖還在,每次還是只能拿到鎖的線程進(jìn)入該方法使線程阻塞,等待時間過長。

3.4 雙重檢查鎖實(shí)現(xiàn)(線程安全)

? 實(shí)現(xiàn):

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

? 說明: 雙重檢查數(shù)相當(dāng)于是改進(jìn)了 線程安全的懶漢式。線程安全的懶漢式 的缺點(diǎn)是性能降低了,造成的原因是因?yàn)榧词箤?shí)例已經(jīng)實(shí)例化,依然每次都會有鎖。而現(xiàn)在,我們將鎖的位置變了,并且多加了一個檢查。 也就是,先判斷實(shí)例是否已經(jīng)存在,若已經(jīng)存在了,則不會執(zhí)行判斷方法內(nèi)的有鎖方法了。 而如果,還沒有實(shí)例化的時候,多個線程進(jìn)去了,也沒有事,因?yàn)槔锩娴姆椒ㄓ墟i,只會讓一個線程進(jìn)入最內(nèi)層方法并實(shí)例化實(shí)例。如此一來,最多最多,也就是第一次實(shí)例化的時候,會有線程阻塞的情況,后續(xù)便不會再有線程阻塞的問題。

? 為什么使用 volatile 關(guān)鍵字修飾了 uniqueInstance 實(shí)例變量 ?

? uniqueInstance = new Singleton(); 這段代碼執(zhí)行時分為三步:

  • 為 uniqueInstance 分配內(nèi)存空間
  • 初始化 uniqueInstance
  • 將 uniqueInstance 指向分配的內(nèi)存地址
  • ? 正常的執(zhí)行順序當(dāng)然是 1>2>3 ,但是由于 JVM 具有指令重排的特性,執(zhí)行順序有可能變成 1>3>2。
    單線程環(huán)境時,指令重排并沒有什么問題;多線程環(huán)境時,會導(dǎo)致有些線程可能會獲取到還沒初始化的實(shí)例。
    例如:線程A 只執(zhí)行了 1 和 3 ,此時線程B來調(diào)用 getUniqueInstance(),發(fā)現(xiàn) uniqueInstance 不為空,便獲取 uniqueInstance 實(shí)例,但是其實(shí)此時的 uniqueInstance 還沒有初始化。

    ? 解決辦法就是加一個 volatile 關(guān)鍵字修飾 uniqueInstance ,volatile 會禁止 JVM 的指令重排,就可以保證多線程環(huán)境下的安全運(yùn)行。

    ? 優(yōu)點(diǎn): 延遲實(shí)例化,節(jié)約了資源;線程安全;并且相對于 線程安全的懶漢式,性能提高了。

    ? 缺點(diǎn): volatile 關(guān)鍵字,對性能也有一些影響。

    3.5 靜態(tài)內(nèi)部類實(shí)現(xiàn)(線程安全)

    ? 實(shí)現(xiàn):

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

    ? 說明: 首先,當(dāng)外部類 Singleton 被加載時,靜態(tài)內(nèi)部類 SingletonHolder 并沒有被加載進(jìn)內(nèi)存。當(dāng)調(diào)用 getUniqueInstance() 方法時,會運(yùn)行 return SingletonHolder.INSTANCE; ,觸發(fā)了 SingletonHolder.INSTANCE ,此時靜態(tài)內(nèi)部類 SingletonHolder 才會被加載進(jìn)內(nèi)存,并且初始化 INSTANCE 實(shí)例,而且 JVM 會確保 INSTANCE 只被實(shí)例化一次。

    ? 優(yōu)點(diǎn): 延遲實(shí)例化,節(jié)約了資源;且線程安全;性能也提高了。

    3.6 枚舉類實(shí)現(xiàn)(線程安全)

    ? 實(shí)現(xiàn):

    public enum Singleton {INSTANCE;//添加自己需要的操作public void doSomeThing() {}}

    ? 說明: 默認(rèn)枚舉實(shí)例的創(chuàng)建就是線程安全的,且在任何情況下都是單例。

    ? 優(yōu)點(diǎn): 寫法簡單,線程安全,天然防止反射和反序列化調(diào)用。

    ? 防止反序列化
    ? **序列化:**把java對象轉(zhuǎn)換為字節(jié)序列的過程;
    ? 反序列化: 通過這些字節(jié)序列在內(nèi)存中新建java對象的過程;
    ? 說明: 反序列化 將一個單例實(shí)例對象寫到磁盤再讀回來,從而獲得了一個新的實(shí)例。我們要防止反序列化,避免得到多個實(shí)例。
    ? 枚舉類天然防止反序列化。
    其他單例模式 可以通過 重寫 readResolve() 方法,從而防止反序列化,使實(shí)例唯一重寫 readResolve() :

    private Object readResolve() throws ObjectStreamException{return singleton; }

    4. 單例模式的應(yīng)用場景

    應(yīng)用場景舉例:

    • 網(wǎng)站計(jì)數(shù)器。
    • 應(yīng)用程序的日志應(yīng)用。
    • Web項(xiàng)目中的配置對象的讀取。
    • 數(shù)據(jù)庫連接池。
    • 多線程池。

    使用場景總結(jié):

    • 頻繁實(shí)例化然后又銷毀的對象,使用單例模式可以提高性能。
    • 經(jīng)常使用的對象,但實(shí)例化時耗費(fèi)時間或者資源多,如數(shù)據(jù)庫連接池,使用單例模式,可以提高性能,降低資源損壞。
    • 使用線程池之類的控制資源時,使用單例模式,可以方便資源之間的通信。

    總結(jié)

    以上是生活随笔為你收集整理的java单例模式与线程安全的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。