日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

设计模式 单例模式

發(fā)布時(shí)間:2025/7/14 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 设计模式 单例模式 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

單例模式

確保一個(gè)類只有一個(gè)實(shí)例,而且自動(dòng)實(shí)例化并向整個(gè)系統(tǒng)提供這個(gè)實(shí)例。

實(shí)現(xiàn)

餓漢式

很簡(jiǎn)單。

  • 將構(gòu)造函數(shù)設(shè)置為私有的,防止外界new出該類的實(shí)例,從而失去了單例的意義。
  • 設(shè)置類的私有靜態(tài)變量,同時(shí)新建單例對(duì)象。
  • 添加共有靜態(tài)方法獲取該單例。
  • 該種方法的缺點(diǎn)是在類加載時(shí)就進(jìn)行實(shí)例化,但是相較于其簡(jiǎn)單易用來說,這點(diǎn)缺點(diǎn)個(gè)人認(rèn)為影響不大。

    package com.mengyunzhi;/*** @author zhangxishuo on 2018/6/18*/ public class Singleton {private static Singleton instance = new Singleton();private Singleton() {}public static Singleton getInstance() {return instance;} }

    這種實(shí)現(xiàn)的單例模式是最簡(jiǎn)單的,同時(shí)多個(gè)線程操作該單例時(shí)也不會(huì)有問題。

    package com.mengyunzhi;public class Main {public static void main(String[] args) {Thread thread1 = new Thread(() -> {Singleton singleton1 = Singleton.getInstance();System.out.println("Singleton1:" + singleton1);});Thread thread2 = new Thread(() -> {Singleton singleton2 = Singleton.getInstance();System.out.println("Singleton2:" + singleton2);});thread1.start();thread2.start();} }

    注:打印時(shí)調(diào)用toString方法,因?yàn)闆]有重寫toString,調(diào)用Object類中的toString,所以打印該對(duì)象的類名加哈希值。

    我們看到控制臺(tái)中打印的兩個(gè)對(duì)象地址都是89ae60d,表示同一塊內(nèi)存,即表示多線程時(shí)該實(shí)現(xiàn)方法仍能實(shí)現(xiàn)單例。

    線程競(jìng)爭(zhēng)

    我們調(diào)用的順序明明是thread1的start,然后thread2再start,但是為什么控制臺(tái)打印的順序卻是單例2和單例1呢?

    這兩個(gè)線程會(huì)競(jìng)爭(zhēng)處理器的資源,這里打印的順序是單例2、單例1,說明處理器處執(zhí)行線程時(shí),先執(zhí)行完thread2線程,后執(zhí)行完thread1線程。這兩個(gè)線程可能是同時(shí)執(zhí)行,也可能是來回切換執(zhí)行,這取決于處理器的核心與線程。

    代碼講解

    函數(shù)式接口

    Thread類的構(gòu)造函數(shù)接收的是一個(gè)Runnable接口類型的參數(shù),所以之前創(chuàng)建線程的代碼長(zhǎng)這樣。

    Thread myThread = new Thread(new Runnable() {@Overridepublic void run() {} });

    看下面的代碼,因?yàn)镽unnable接口只有一個(gè)抽象的run方法需要去實(shí)現(xiàn),所以就不需要去@Override聲明我要實(shí)現(xiàn)run方法,直接傳一個(gè)函數(shù)體不就可以嗎?這就是函數(shù)式接口。

    package java.lang;@FunctionalInterface public interface Runnable {public abstract void run(); }

    lamda表達(dá)式

    相信很多人都聽說過lamda表達(dá)式,但是總是覺得這個(gè)很高大上,其實(shí)我們接觸過lamda表達(dá)式,只是沒有注意到。

    self.init = function() {};

    在JavaScript的世界里,我們可以將一個(gè)函數(shù)傳來傳去。

    self.init = () => {};

    然后人們發(fā)現(xiàn),寫function太麻煩了,他們發(fā)明了箭頭函數(shù)。用這種寫法代替一個(gè)函數(shù)。

    那Java為什么不可以?

    如果剛剛的代碼這么寫,那你應(yīng)該瞬間就明白了。

    Runnable runnable = () -> {Singleton singleton1 = Singleton.getInstance();System.out.println("Singleton1:" + singleton1); }; Thread thread1 = new Thread(runnable);

    懶漢式

    這是懶漢式的寫法,當(dāng)需要這個(gè)實(shí)例的時(shí)候,再去新建實(shí)例。

    package com.mengyunzhi;/*** @author zhangxishuo on 2018/6/18*/ public class Singleton {private static Singleton instance;private Singleton() {}public static Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;} }

    但是這是這種寫法是線程不安全的,我們?cè)龠\(yùn)行一下主函數(shù)中多個(gè)線程同時(shí)訪問單例的方法。

    上次向晨澍請(qǐng)教:StringBuffer線程安全,StringBuilder線程不安全。既然有的類線程安全,有的類線程不安全?那為什么不都用線程安全的呢?

    答案就是:為了實(shí)現(xiàn)線程安全,系統(tǒng)需要額外的開銷。所以有些不需要多線程的,使用線程不全的類,通常會(huì)提高速度。

    假設(shè)我們的處理器支持多個(gè)線程并行處理,當(dāng)多個(gè)線程同時(shí)訪問時(shí),thread1獲取實(shí)例,然后判斷if (instance == null),創(chuàng)建實(shí)例;另一個(gè)線程同時(shí)執(zhí)行,instance依然是空,然后thread2調(diào)用getInstance時(shí)又創(chuàng)建了一個(gè)實(shí)例。這就違反了單例模式。

    synchronized

    解決該問題的方案就是用synchronized修飾該代碼塊。

    音標(biāo):['s??kr?na?zd]

    只允許一個(gè)線程訪問synchronized修飾的代碼塊,其他線程會(huì)被阻塞,等待該線程執(zhí)行完再執(zhí)行。

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

    應(yīng)該是線程2先執(zhí)行完的,所以我們猜測(cè)就是:線程2競(jìng)爭(zhēng)到處理器資源,然后去訪問getInstance()方法,因?yàn)楣P者屬于多核多線程處理器,支持線程并行執(zhí)行,當(dāng)線程2訪問getInstance()代碼塊時(shí),因?yàn)橛衧ynchronized修飾,所以線程1會(huì)被阻塞,等待線程2執(zhí)行完再才能訪問該代碼塊。

    線程2執(zhí)行完創(chuàng)建實(shí)例,線程1可以訪問該代碼塊,發(fā)現(xiàn)instance不為空,直接返回。

    使用場(chǎng)景

    • 頻繁new然后銷毀的對(duì)象,降低了內(nèi)存開支。
    • 當(dāng)一個(gè)對(duì)象的產(chǎn)生需要較多資源時(shí),如讀取配置,可以將其設(shè)置為單例,在應(yīng)用啟動(dòng)時(shí)產(chǎn)生一個(gè)單例對(duì)象常駐內(nèi)存。
    • 單例是同一個(gè)對(duì)象,可以用該單例設(shè)置項(xiàng)目配置,用于幾個(gè)模塊之間共享。

    擴(kuò)展:多線程學(xué)習(xí)

    為什么要使用多線程?

    摩爾定律

    每18個(gè)月,芯片的性能將提高一倍。

    單核心

    十幾年前,那時(shí)還是單核的時(shí)代,各大廠商做出主頻越來越高的處理器。

    但是主頻越高,意味著芯片中需要的晶體管越多,功耗越大,散熱越多,當(dāng)一定程度熱量就會(huì)燒壞芯片。

    為什么CPU的頻率止步于4G?我們觸到頻率天花板了嗎?

    2004年秋,Intel的CEO公開對(duì)取消4GHz芯片的計(jì)劃道歉。

    這是Intel酷睿i7 8700K的參數(shù),主頻僅有3.70GHz,十幾年過去了,我們依然停留在4GHz。

    多核心

    但是,為了滿足不斷增長(zhǎng)的用戶需求,雖然無法提升單個(gè)核心的時(shí)鐘頻率,但是廠商利用多核心實(shí)現(xiàn)了芯片的性能提升。

    這是Intel官網(wǎng)對(duì)i7 8700K的描述,6核心12線程。也就是說這個(gè)處理器有6個(gè)物理核心,因?yàn)槌€程技術(shù),可以模擬出12個(gè)邏輯核心,即可以同時(shí)處理12個(gè)線程任務(wù)。

    超線程就是利用處理器剩余的資源模擬出一個(gè)新的核心,用于提高處理器的利用率。

    《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀

    總結(jié)

    以上是生活随笔為你收集整理的设计模式 单例模式的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

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