Java與Kotlin的單例模式(霸氣.jpg)

作者已經(jīng)搬遷去隔壁網(wǎng)站鲜结,也歡迎大家關(guān)注我們的寫作團(tuán)隊:天星技術(shù)團(tuán)隊媒至。

題外話

上一次被人說文章名字取得不霸氣今膊,于是這一次我采用了這么霸氣的名字崎苗,但實際上我是一個很低調(diào)的人狐粱。設(shè)計模式剛?cè)腴T的小伙伴可以先看看這篇《設(shè)計模式入門》,在文章末尾也將列出“設(shè)計模式系列”文章胆数。歡迎大家關(guān)注留言投幣丟香蕉肌蜻。

什么是單例模式

  1. 單例模式是設(shè)計模式中最簡單的形式之一。
  2. 一個類有且僅有一個對象實例必尼,并自行實例化向整個系統(tǒng)提供蒋搜。

為何要學(xué)習(xí)單例模式

1. 有些對象我們只需要一個。例如:線程池,緩存齿诞,對話框等等酸休,創(chuàng)建太多此類實例可能會導(dǎo)致程序行為異常、資源使用過量等問題祷杈。
2. 防止造成資源浪費(fèi)。靜態(tài)變量也可以給整個系統(tǒng)提供一個實例渗饮,但此對象在程序一開始就被創(chuàng)建好了但汞,萬一在某次運(yùn)行中沒有使用到此對象,資源就被浪費(fèi)了互站。
3. 沒有富蘿莉包養(yǎng)我私蕾。

走進(jìn)單例模式

單例模式有三個要點,分別是:
1. 僅有一個實例胡桃。
2. 自動實例化踩叭。
3. 向整個系統(tǒng)提供。
這也就是我們在寫單例模式時候必須要遵守的幾點翠胰。根據(jù)上面的條件容贝,我們能夠得出:
1. 構(gòu)造方法必須私有化,禁止外部隨意new Singleton()之景;
2. 類內(nèi)部實例化一個實例對象斤富。
3. 對外提供一個可以獲取內(nèi)部唯一實例對象的方法。

懶漢式

懶漢式這名字的精髓在于懶锻狗,在代碼中满力,這種懶代表著需要的時候才創(chuàng)建實例,不需要就不創(chuàng)建了轻纪,這樣保證了資源的不浪費(fèi)油额。

Java懶漢式

public class JavaSingleton {

    private JavaSingleton(){}//私有構(gòu)造方法
    private static JavaSingleton instance;//提供一個實例對象

     public static JavaSingleton getInstance(){//對外提供可獲取唯一實例化對象的方法
        if(instance == null)
            instance = new JavaSingleton(); //延遲實例化
        return instance;
    }
}

Kotlin懶漢式1

class KotlinSingleton private constructor() {
    private var instance : KotlinSingleton? = null

    fun getInstance(): KotlinSingleton? {
        if(instance == null)
            instance = KotlinSingleton()
        return instance
    }
}

Kotlin懶漢式2

class KotlinSingleton private constructor() {
    companion object {
        val instance by lazy(LazyThreadSafetyMode.NONE) {
            KotlinSingleton()
        }
    }
}

// 在Kotlin 中調(diào)用
KotlinSingleton.instance.xx()
// 在Java 中調(diào)用
KotlinSingleton.Companion.getInstance().xx()

kotlin方式1就是直譯了java方式,沒啥說的刻帚。kotlin方式2寫著很簡潔潦嘶,也很明了。要提一點的就是companion object我擂,他類似public static衬以,這一點從下面調(diào)用方式也看得出來。lazy屬性表明是懶加載方式校摩,LazyThreadSafetyMode.NONE表明了這種方式看峻,線程不安全。
為啥不安全衙吩?互妓?!!
我們已經(jīng)按照單例模式三個要點寫出了單例模式冯勉,其實都已經(jīng)講完了澈蚌。但為何還有其他一些寫法呢? 因為我們是程序員白普宛瞄!優(yōu)化!優(yōu)化交胚!優(yōu)化份汗!
單線程進(jìn)程下,懶漢式完全夠用蝴簇。但實際開發(fā)哪還有什么單線程程序杯活。既然存在多線程,就存在并發(fā)性熬词,如果兩個線程同時進(jìn)入非空判斷旁钧,問題就出現(xiàn)了。線程一可能創(chuàng)建了一個instance互拾,線程二因為已經(jīng)非空判斷為空了歪今,所以也創(chuàng)建了個instance。這樣程序肯定不會朝著你預(yù)想的方向去摩幔。所以我們可以給非空判斷加一把鎖彤委,防止多線程同時進(jìn)入非空判斷。

同步鎖

Java方式

public class JavaSingleton {

    private JavaSingleton(){}//私有構(gòu)造方法
    private static JavaSingleton instance;//提供一個實例對象

     public static synchronized JavaSingleton getInstance(){//對外提供可獲取唯一實例化對象的方法
        if(instance == null)
            instance = new JavaSingleton(); //延遲實例化
        return instance;
    }
}

Kotlin方式

class KotlinSingleton private constructor() {
    private var instance : KotlinSingleton? = null

    @Synchronized //用注解就okk了或衡。
    fun getInstance(): KotlinSingleton? {
        if(instance == null)
            instance = KotlinSingleton()
        return instance
    }
}

簡單焦影!粗暴!
太粗暴了封断!Synchronized 是一把重型鎖斯辰,對性能影響相當(dāng)?shù)拇螅駟卫@樣在軟件中可能多次獲取坡疼,那性能將會大大地降低彬呻!所以,這種方式不建議使用柄瑰。

餓漢式

為了解決多線程的問題闸氮,又不想降低性能,“餓漢式”就來了教沾。餓漢式名字精髓在于“餓”蒲跨,迫切的想吃東西,在代碼中表示授翻,迫切的想有一個單例對象或悲!即在初始化的時候孙咪,就把單例創(chuàng)建好,之后要用就直接return巡语,但是不用就浪費(fèi)了翎蹈。這也是餓漢式的缺點。
Java方式

public class JavaSingleton {

    private JavaSingleton(){}//私有構(gòu)造方法
    private static JavaSingleton instance = new JavaSingleton();//提供一個實例對象

    public static JavaSingleton getInstance(){//對外提供可獲取唯一實例化對象的方法
        return instance;
    }
}

Kotlin方式

object KotlinSingleton {
    //null
}

// 在Kotlin 中調(diào)用
KotlinSingleton.xx()
// 在Java 中調(diào)用
KotlinSingleton.INSTANCE.xx()

酥糊男公!Kotlin荤堪!有牌面!

雙重檢查鎖

前面講的三種方式都有不同程度的缺點枢赔。而雙重檢查鎖逞力,既保證了延遲加載不浪費(fèi)資源,又保證了較好的性能糠爬,不采用重型鎖。但雙重檢查鎖不適用于1.4以及更早版本的java举庶。

Java方式

public class JavaSingleton {

    private JavaSingleton(){}
    //volatile確保了當(dāng)instance初始化為JavaSingleton實例時执隧,多個線程正確的處理instance變量。
    private volatile static JavaSingleton instance;

   public static JavaSingleton getInstance(){
       if(instance == null){
           synchronized (JavaSingleton.class){//只有第一次才徹底執(zhí)行鎖塊代碼
               if(instance == null){
                   instance = new JavaSingleton();
               }
           }
       }
       return instance;
   }
}

Kotlin方式1

class KotlinSingleton private constructor() {
    @Volatile  //用注解就okk了
    private var instance : KotlinSingleton? = null

    fun getInstance(): KotlinSingleton? {
        if(instance == null){
            synchronized(KotlinSingleton::class){
                if(instance == null){
                    instance = KotlinSingleton()
                }
            }
        }
        return instance
    }
}

Kotlin方式2

class KotlinSingleton private constructor() {
    companion object {
        val instance by lazy (LazyThreadSafetyMode.SYNCHRONIZED){
            KotlinSingleton()
        }
    }
}

// 在Kotlin 中調(diào)用
KotlinSingleton.instance.xx()
// 在Java 中調(diào)用
KotlinSingleton.Companion.getInstance().xx()

“雙重檢查鎖”的沒有明顯的缺點户侥,如果非要說一個镀琉,可能就是太復(fù)雜了。kotlin還好蕊唐,java里面寫著相當(dāng)?shù)膹?fù)雜屋摔。如果程序?qū)π阅軟]有考慮的話,這樣寫顯然就太麻煩了替梨。

關(guān)于LazyThreadSafetyMode
延遲屬性 Lazy 可選LazyThreadSafetyMode三種模式:

  • SYNCHRONIZED —— 雙重檢查鎖式钓试,默認(rèn)使用。
  • PUBLICATION —— 允許多個線程同時初始化實例副瀑,但只采用最先返回的實例弓熏。
  • NONE —— 沒有任何的線程安全的保證和開銷。

內(nèi)部類式(店長推薦?匪M炀稀)

不要私信問我店長是誰!
總之這種方式狈孔,解決了延遲加載信认,線程安全的問題,還代碼量少均抽!簡直美滋滋嫁赏!但跟之前不同的是,沒有聲明實例對象到忽。
Java方式

public class JavaSingleton {

    private JavaSingleton(){}

    private static class Holder{
        private static JavaSingleton instance = new JavaSingleton();
    }

    public static JavaSingleton getInstance(){
        return Holder.instance;
    }
}

Kotlin方式

class KotlinSingleton private constructor() {
    companion object {
        fun getInstance() = Holder.instance
    }

    private object Holder{
        val instance = KotlinSingleton()
    }
}

在類加載時橄教,因為沒有調(diào)用getInstance()所以Holder也不會加載清寇,這樣就實現(xiàn)了懶加載。調(diào)用getInstance()時护蝶,JVM會主動保證類加載的安全性华烟,所以線程也是安全的。kotlin的寫法就是java的翻譯版本持灰。

民間大神版本

上面幾種方式都是比較官方的版本盔夜,下面介紹幾個民間版本,是真大神還是抖機(jī)靈堤魁,自行判斷喂链。我也去研究研究!


來自知乎@丌冰:
“我覺得這樣就好了妥泉,什么懶加載椭微,雙重什么什么,什么什么的”

fun main(args: Array<String>) {
    Instance.INSTANCE.fun1()
    print(Instance.INSTANCE.fun2())
}
enum class Instance {
    INSTANCE;

    fun fun1(){
    }
    fun fun2():Any?{
        return null
    }
}

作者:丌冰
鏈接:https://www.zhihu.com/question/52377186/answer/303561470
來源:知乎
著作權(quán)歸作者所有盲链。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán)蝇率,非商業(yè)轉(zhuǎn)載請注明出處。

可見Android官方并不推薦使用枚舉刽沾,占用內(nèi)存較多本慕。

來自劉望舒設(shè)計模式(二)單例模式的七種寫法

public class SingletonManager { 
  private static Map<String, Object> objMap = new HashMap<String,Object>();
  private Singleton() { 
  }
  public static void registerService(String key, Objectinstance) {
    if (!objMap.containsKey(key) ) {
      objMap.put(key, instance) ;
    }
  }
  public static ObjectgetService(String key) {
    return objMap.get(key) ;
  }
}

這也是比較少見的單例寫法,將多個單例放在進(jìn)SingletonManager 的靜態(tài)map中統(tǒng)一管理侧漓。我是覺得有點太過于復(fù)雜锅尘,容易出錯。

以上版本僅供參考布蔗,要是用了對程序造成了什么不好的影響藤违,別找我。

關(guān)于單例的其他問題

關(guān)于繼承: 不能繼承何鸡!別想了纺弊。
關(guān)于單例: 盡量少使用單例。
關(guān)于我還沒想到的問題: 歡迎加群討論557247785骡男。

總結(jié)

單例方式 優(yōu)點 缺點
懶漢式 懶加載 線程不安全
同步鎖 線程安全 多次獲取的性能很低
餓漢式 簡單淆游、易寫 可能引起資源浪費(fèi)
雙重檢查鎖 第一次獲取才加鎖 寫法復(fù)雜
內(nèi)部類式 簡單、易寫 暫無
民間大神式 歡迎留言跟我討論 或者加qq群:557247785

以下是我“設(shè)計模式系列”文章隔盛,歡迎大家關(guān)注留言投幣丟香蕉犹菱。
也可以進(jìn)群跟大神們討論。qq群:557247785

設(shè)計模式入門
Java與Kotlin的單例模式
Kotlin的裝飾者模式與源碼擴(kuò)展
由淺到深了解工廠模式
為了學(xué)習(xí)Rxjava吮炕,年輕小伙竟作出這種事腊脱!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市龙亲,隨后出現(xiàn)的幾起案子陕凹,更是在濱河造成了極大的恐慌悍抑,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件杜耙,死亡現(xiàn)場離奇詭異搜骡,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)佑女,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進(jìn)店門记靡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人团驱,你說我怎么就攤上這事摸吠。” “怎么了嚎花?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵寸痢,是天一觀的道長。 經(jīng)常有香客問我紊选,道長轿腺,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任丛楚,我火速辦了婚禮,結(jié)果婚禮上憔辫,老公的妹妹穿的比我還像新娘趣些。我一直安慰自己,他們只是感情好贰您,可當(dāng)我...
    茶點故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布坏平。 她就那樣靜靜地躺著,像睡著了一般锦亦。 火紅的嫁衣襯著肌膚如雪舶替。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天杠园,我揣著相機(jī)與錄音顾瞪,去河邊找鬼。 笑死抛蚁,一個胖子當(dāng)著我的面吹牛陈醒,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播瞧甩,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼钉跷,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了肚逸?” 一聲冷哼從身側(cè)響起爷辙,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤彬坏,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后膝晾,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體栓始,經(jīng)...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年玷犹,在試婚紗的時候發(fā)現(xiàn)自己被綠了混滔。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡歹颓,死狀恐怖坯屿,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情巍扛,我是刑警寧澤领跛,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站撤奸,受9級特大地震影響吠昭,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜胧瓜,卻給世界環(huán)境...
    茶點故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一矢棚、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧府喳,春花似錦蒲肋、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至弯蚜,卻和暖如春孔轴,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背碎捺。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工路鹰, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人收厨。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓悍引,卻偏偏與公主長得像,于是被迫代替她去往敵國和親帽氓。 傳聞我的和親對象是個殘疾皇子趣斤,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,871評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 單例模式(SingletonPattern)一般被認(rèn)為是最簡單、最易理解的設(shè)計模式黎休,也因為它的簡潔易懂浓领,是項目中最...
    成熱了閱讀 4,253評論 4 34
  • 在一個方法內(nèi)部定義的變量都存儲在棧中玉凯,當(dāng)這個函數(shù)運(yùn)行結(jié)束后,其對應(yīng)的棧就會被回收联贩,此時漫仆,在其方法體中定義的變量將不...
    Y了個J閱讀 4,417評論 1 14
  • 1.單例模式概述 (1)引言 單例模式是應(yīng)用最廣的模式之一,也是23種設(shè)計模式中最基本的一個泪幌。本文旨在總結(jié)通過Ja...
    曹豐斌閱讀 2,920評論 6 47
  • 這貨書名夠風(fēng)騷盲厌,內(nèi)容夠羅嗦,逼格略低祸泪,這是多大仇啊吗浩。不過內(nèi)容夠詳細(xì),邏輯完整的讓人抓狂没隘,淺顯易懂懂扼。還有盡是泛泛之談...
    拉斯閱讀 409評論 0 0