偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

單例模式深度解析:從餓漢式到枚舉實現(xiàn)的全方位解讀

開發(fā) 前端
就是采取一定的方法保證在整個的軟件系統(tǒng)中,對某個類只能存在一個對象實例,并且該類只提供一個取得其對象實例的方法。

單例設(shè)計模式概念

就是采取一定的方法保證在整個的軟件系統(tǒng)中,對某個類只能存在一個對象實例,并且該類只提供一個取得其對象實例的方法。如果我們要讓類在一個虛擬機中只能產(chǎn)生一個對象,我們首先必須將類的構(gòu)造器的訪問權(quán)限設(shè)置為private,這樣,就不能用new操作符在類的外部產(chǎn)生類的對象了,但在類內(nèi)部仍可以產(chǎn)生該類的對象。因為在類的外部開始還無法得到類的對象,只能調(diào)用該類的某個靜態(tài)方法以返回類內(nèi)部創(chuàng)建的對象,靜態(tài)方法只能訪問類中的靜態(tài)成員變量,所以,指向類內(nèi)部產(chǎn)生的該類對象的變量也必須定義成靜態(tài)的。

餓漢式

class Singleton {
    // 1.私有化構(gòu)造器
    private Singleton() {
    }
    // 2.內(nèi)部提供一個當前類的實例
    // 4.此實例也必須靜態(tài)化
    private static Singleton single = new Singleton();
    // 3.提供公共的靜態(tài)的方法,返回當前類的對象;在內(nèi)存中自始至終都存在
    public static Singleton getInstance() {
        return single;
    }
}

案例:

public static void main(String[] args) {
        User user1 = User.getUser();
        System.out.println(user1);
        User user2 = User.getUser();
        System.out.println(user2);
}
class User{
    //1、私有化構(gòu)造器
    private User() {
    }
    //2、內(nèi)部提供一個當前類的實例,此實例也必須靜態(tài)化
    private static User user = new User();
    //3、提供公共的靜態(tài)的方法,返回當前類的對象;在內(nèi)存中自始至終都存在
    public static User getUser() {
        return user;
    }
}
//結(jié)果是一樣的,即同一個對象
com.gupao.singleton.User@6d6f6e28
com.gupao.singleton.User@6d6f6e28

static變量在類加載的時候初始化,此時不會涉及到多個線程對象訪問該對象的問題,虛擬機保證只會裝載一次該類,肯定不會發(fā)生并發(fā)問題,無需使用synchronized 關(guān)鍵字

存在的問題:如果只是加載了本類,而并不需要調(diào)用getUser,則會造成資源的浪費。

總結(jié):線程安全、非懶加載、效率高,資源浪費

懶漢式

延遲對象的創(chuàng)建

方式1:普通創(chuàng)建

public class Singleton {
    //私有構(gòu)造方法
    private Singleton() {}

    //在成員位置創(chuàng)建該類的對象
    private static Singleton instance;

    //對外提供靜態(tài)方法獲取該對象
    public static Singleton getInstance() {

        if(instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

如果是多線程環(huán)境,以上代碼會出現(xiàn)線程安全問題。

方式2:方法加鎖

class Singleton {
    // 1.私有化構(gòu)造器
    private Singleton() {
    }
    // 2.內(nèi)部提供一個當前類的實例
    // 4.此實例也必須靜態(tài)化
    private static Singleton instance;
    // 3.提供公共的靜態(tài)的方法,返回當前類的對象
    public static synchronized Singleton getInstance() {//注意多線程情況
        if(instance== null) {
        instance= new Singleton();
        }
    return instance;
    }
}

以上使用同步方法會造成每次獲取實例的線程都要等鎖,會對系統(tǒng)性能造成影響,未能完全發(fā)揮系統(tǒng)性能,可使用同步代碼塊來解決

方式3:雙重檢查鎖

對于 getInstance() 方法來說,絕大部分的操作都是讀操作,讀操作是線程安全的,所以我們沒必讓每個線程必須持有鎖才能調(diào)用該方法,我們需要調(diào)整加鎖的時機。由此也產(chǎn)生了一種新的實現(xiàn)模式:雙重檢查鎖模式

public class Singleton { 

    //私有構(gòu)造方法
    private Singleton() {}

    private volatile static Singleton instance;

   //對外提供靜態(tài)方法獲取該對象
    public static Singleton getInstance() {
  //第一次判斷,如果instance不為null,不進入搶鎖階段,直接返回實例
        if(instance == null) { // ①
            synchronized (Singleton.class) {
                //搶到鎖之后再次判斷是否為null
                if(instance == null) {
                    instance = new Singleton();// ②
                }
            }
        }
        return instance;
    }
}

為什么判斷兩次instance==null

第一次判斷是在代碼塊前,第二次是進入代碼塊后,第二個判斷想必都知道,多個線程都堵到代碼塊前等待鎖的釋放,進入代碼塊后要獲取到最新的instance值,如果為空就進行創(chuàng)建對象。那么為什么還要進行第一個判斷,第一個判斷起到優(yōu)化作用,假設(shè)如果instance已經(jīng)不為空了,那么沒有第一個判斷仍然會有線程堵在代碼塊前等待進一步判斷,所以如果不為空,有了第一個判斷就不用再去進入代碼塊進行判斷,也就不用再去等鎖了,直接返回。

為什么要加volatile?

  • 是為了防止指令重排序,給私有變量加 volatile 主要是為了防止第 ② 處執(zhí)行時,也就是“instance = new Singleton()”執(zhí)行時的指令重排序的,這行代碼看似只是一個創(chuàng)建對象的過程,然而它的實際執(zhí)行卻分為以下 3 步:

試想一下,如果不加 volatile,那么線程A在執(zhí)行到上述代碼的第 ② 處時就可能會執(zhí)行指令重排序,將原本是 1、2、3 的執(zhí)行順序,重排為 1、3、2。但是特殊情況下,線程 A在執(zhí)行完第 3 步之后,如果來了線程 B執(zhí)行到上述代碼的第 ① 處,判斷 instance 對象已經(jīng)不為 null,但此時線程 A還未將對象實例化完,那么線程B將會得到一個被實例化“一半”的對象,從而導致程序執(zhí)行出錯,這就是為什么要給私有變量添加 volatile 的原因了。

  1. 創(chuàng)建內(nèi)存空間。
  2. 在內(nèi)存空間中初始化對象 Singleton。
  3. 將內(nèi)存地址賦值給 instance 對象(執(zhí)行了此步驟,instance 就不等于 null 了)。
  • 優(yōu)化作用,synchronized塊只有執(zhí)行完才會同步到主內(nèi)存,那么比如說instance剛創(chuàng)建完成,不為空,但還沒有跳出synchronized塊,此時又有10000個線程調(diào)用方法,那么如果沒有volatile,此使instance在主內(nèi)存中仍然為空,這一萬個線程仍然要通過第一次判斷,進入代碼塊前進行等待,正是有了volatile,一旦instance改變,那么便會同步到主內(nèi)存,即使沒有出synchronized塊,instance仍然同步到了主內(nèi)存,通過不了第一個判斷也就避免了新加的10000個線程進入去爭取鎖。

總結(jié):線程安全、懶加載、效率高。

靜態(tài)內(nèi)部類(延遲初始化占位類)

靜態(tài)內(nèi)部類單例模式中實例由內(nèi)部類創(chuàng)建,由于 JVM 在加載外部類的過程中, 是不會加載靜態(tài)內(nèi)部類的, 只有內(nèi)部類的屬性/方法被調(diào)用時才會被加載, 并初始化其靜態(tài)屬性。靜態(tài)屬性由于被 static 修飾,保證只被實例化一次,并且嚴格保證實例化順序。

public class Singleton {

    private Singleton() {
    }

    private static class SingletonHolder{
        private  static final Singleton Instance = new Singleton();
    }

    public static Singleton getInstance(){
        return SingletonHolder.Instance;
    }
}

第一次加載Singleton類時不會去初始化INSTANCE,只有第一次調(diào)用getInstance,虛擬機加載SingletonHolder并初始化INSTANCE,這樣不僅能確保線程安全,也能保證 Singleton 類的唯一性。

靜態(tài)內(nèi)部類單例模式是一種優(yōu)秀的單例模式,是開源項目中比較常用的一種單例模式。在沒有加任何鎖的情況下,保證了多線程下的安全,并且沒有任何性能影響和空間的浪費。

總結(jié):線程安全、懶加載、效率高。

枚舉

枚舉類實現(xiàn)單例模式是極力推薦的單例實現(xiàn)模式,因為枚舉類型是線程安全的,并且只會裝載一次,設(shè)計者充分的利用了枚舉的這個特性來實現(xiàn)單例模式,枚舉的寫法非常簡單,而且枚舉類型是所用單例實現(xiàn)中唯一一種不會被破壞的單例實現(xiàn)模式。

public enum Singleton {

     INSTANCE;

}

提供了序列化機制,保證線程安全,絕對防止多次實例化,即使是在面對復(fù)雜的序列化或者反射攻擊的時候。

枚舉方式屬于餓漢式方式,會浪費資源

總結(jié):線程安全、非懶加載、效率高。

幾種方式對比

方式

優(yōu)點

缺點

餓漢式

線程安全、效率高

非懶加載,資源浪費

懶漢式synchronized方法

線程安全、懶加載

效率低

懶漢式雙重檢測

線程安全、懶加載、效率高

靜態(tài)內(nèi)部類

線程安全、懶加載、效率高

枚舉

線程安全、效率高

非懶加載,資源浪費

責任編輯:武曉燕 來源: seven97
相關(guān)推薦

2016-12-14 14:43:11

ButterknifeAndroid

2009-12-15 10:10:42

Ruby過程對象

2011-10-26 09:28:28

紅帽大數(shù)據(jù)Gluster

2010-01-04 14:06:35

Silverlight

2009-08-24 10:39:12

思科認證CCNA思科認證CCNA

2009-12-21 13:06:05

WCF Address

2009-12-16 17:07:27

Ruby on Rai

2009-12-15 10:48:54

Ruby局部變量

2010-01-27 13:52:15

Android多媒體框

2014-06-26 17:25:22

車聯(lián)網(wǎng) ECU

2009-12-14 17:04:13

Ruby讀寫UNIX命

2022-05-23 07:35:15

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

2011-06-15 14:33:13

2009-09-17 09:01:10

CCNA學習指南CCNA

2009-12-21 15:48:29

WCF應(yīng)用程序

2024-05-10 14:35:56

人工智能大型語言模型

2010-01-05 09:57:34

.NET Framew

2021-07-21 08:20:24

微信搜索功能設(shè)計

2013-03-01 09:56:57

2016-02-16 14:42:58

戴爾云計算
點贊
收藏

51CTO技術(shù)棧公眾號