成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

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

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

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

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

餓漢式

class Singleton {
    // 1.私有化構(gòu)造器
    private Singleton() {
    }
    // 2.內(nèi)部提供一個(gè)當(dāng)前類的實(shí)例
    // 4.此實(shí)例也必須靜態(tài)化
    private static Singleton single = new Singleton();
    // 3.提供公共的靜態(tài)的方法,返回當(dāng)前類的對(duì)象;在內(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)部提供一個(gè)當(dāng)前類的實(shí)例,此實(shí)例也必須靜態(tài)化
    private static User user = new User();
    //3、提供公共的靜態(tài)的方法,返回當(dāng)前類的對(duì)象;在內(nèi)存中自始至終都存在
    public static User getUser() {
        return user;
    }
}
//結(jié)果是一樣的,即同一個(gè)對(duì)象
com.gupao.singleton.User@6d6f6e28
com.gupao.singleton.User@6d6f6e28

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

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

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

懶漢式

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

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

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

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

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

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

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

方式2:方法加鎖

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

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

方式3:雙重檢查鎖

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

public class Singleton { 

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

    private volatile static Singleton instance;

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

為什么判斷兩次instance==null

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

為什么要加volatile?

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

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

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

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

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

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

public class Singleton {

    private Singleton() {
    }

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

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

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

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

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

枚舉

枚舉類實(shí)現(xiàn)單例模式是極力推薦的單例實(shí)現(xiàn)模式,因?yàn)槊杜e類型是線程安全的,并且只會(huì)裝載一次,設(shè)計(jì)者充分的利用了枚舉的這個(gè)特性來(lái)實(shí)現(xiàn)單例模式,枚舉的寫(xiě)法非常簡(jiǎn)單,而且枚舉類型是所用單例實(shí)現(xiàn)中唯一一種不會(huì)被破壞的單例實(shí)現(xiàn)模式。

public enum Singleton {

     INSTANCE;

}

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

枚舉方式屬于餓漢式方式,會(huì)浪費(fèi)資源

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

幾種方式對(duì)比

方式

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

缺點(diǎn)

餓漢式

線程安全、效率高

非懶加載,資源浪費(fèi)

懶漢式synchronized方法

線程安全、懶加載

效率低

懶漢式雙重檢測(cè)

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

無(wú)

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

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

無(wú)

枚舉

線程安全、效率高

非懶加載,資源浪費(fèi)

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

2016-12-14 14:43:11

ButterknifeAndroid

2009-12-15 10:10:42

Ruby過(guò)程對(duì)象

2011-10-26 09:28:28

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

2010-01-04 14:06:35

Silverlight

2009-08-24 10:39:12

思科認(rèn)證CCNA思科認(rèn)證CCNA

2009-12-15 10:48:54

Ruby局部變量

2014-06-26 17:25:22

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

2010-01-27 13:52:15

Android多媒體框

2009-12-14 17:04:13

Ruby讀寫(xiě)UNIX命

2009-12-21 13:06:05

WCF Address

2009-12-16 17:07:27

Ruby on Rai

2022-05-23 07:35:15

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

2009-12-21 15:48:29

WCF應(yīng)用程序

2009-09-17 09:01:10

CCNA學(xué)習(xí)指南CCNA

2011-06-15 14:33:13

2010-01-05 09:57:34

.NET Framew

2024-05-10 14:35:56

人工智能大型語(yǔ)言模型

2021-07-21 08:20:24

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

2013-03-01 09:56:57

2016-02-16 14:42:58

戴爾云計(jì)算
點(diǎn)贊
收藏

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

主站蜘蛛池模板: 欧美日韩精品久久久免费观看 | 午夜男人视频 | 亚洲精品区 | 久久com| 99久久久久国产精品免费 | 黄色毛片一级 | 美女人人操 | 福利网址| 国产激情一区二区三区 | 亚洲91精品| 国产高清区 | 中文精品久久 | 精品二区 | 红桃成人在线 | 国产一区二区精品在线观看 | 亚洲韩国精品 | 亚洲伊人久久综合 | 成人欧美一区二区三区在线观看 | 中文字幕 在线观看 | 欧美精品1区2区3区 精品国产欧美一区二区 | 国产高清精品一区二区三区 | 日韩电影免费在线观看中文字幕 | 精品综合久久久 | www.三级 | av一区二区三区四区 | 精品国产一区二区三区免费 | 一区二区在线视频 | 久久久久久久国产 | 91久久精品视频 | 日韩成人免费视频 | 国产精品激情在线 | 亚洲成a人片 | 精品成人一区二区 | 天天玩夜夜操 | www精品美女久久久tv | 日韩国产精品一区二区三区 | 国产精品亚洲一区 | 午夜精品久久久久久久久久久久 | 三级免费网 | 国产成人免费视频网站高清观看视频 | 久久久久久久一级 |