更完整的單例模式(java, kotlin)

前言

java 常見(jiàn)的單例模式有三種:

  • 懶漢: getInstance的時(shí)候?qū)嵗?
  • 餓漢: 引用AA類的時(shí)候?qū)嵗? 例如 AA.fun() 或者 AA.getInstance();
  • 靜態(tài)內(nèi)部類: getInstance的時(shí)候?qū)嵗? 寫(xiě)法比懶漢要簡(jiǎn)單;

個(gè)人理解:
如果沒(méi)有除了getInstance 方法之外的 public static fun 的話, 以上三種單例模式在加載時(shí)間上基本是沒(méi)有差別的. 考慮到實(shí)現(xiàn)比較輕松, 推薦靜態(tài)內(nèi)部類方式創(chuàng)建單例.


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

public class AA {
    private static class Holder{
        private static AA instance = new AA();
    }
    
    private AA(){}
    
    public static AA getInstance(){
        return Holder.instance;
    }
}

java 懶漢模式

  1. 比較簡(jiǎn)單的寫(xiě)法是這樣:

    public class AA {
        private static AA instance;
        public static AA getInstance(){
            if(instance == null){
                AA = new AA();
            }
            return instance;
        }
    }
    
  2. 但上面這樣寫(xiě)不是線程安全的, 如果多線程同時(shí)調(diào)用 getInstance 時(shí), 有可能同時(shí)通過(guò) instance==null 的判斷, 導(dǎo)致執(zhí)行兩遍 new AA , 所以需要加鎖, 改進(jìn)寫(xiě)法:

    public class AA {
        private static AA instance;
        public static AA getInstance(){
            if(instance == null){
                synchronized(AA.class){
                    if(instance == null){
                        AA = new AA();
                    }
                }
            }
            return instance;
        }
    }
    
  1. 但這樣還是有漏洞, jvm 有指令重排機(jī)制, 臨界情況下的靠后者有可能會(huì)得到一個(gè)初始化尚未完成的 instance 對(duì)象, 這時(shí)需要加 volatile 修飾符, 這個(gè)修飾符能組織變量訪問(wèn)前后的指令重排, 改進(jìn)寫(xiě)法:

    public class AA {
        private volatile static AA instance;
        public static AA getInstance(){
            if(instance == null){
                synchronized(AA.class){
                    if(instance == null){
                        AA = new AA();
                    }
                }
            }
            return instance;
        }
    }
    

kotlin 的單例模式

  • 惡漢 --> 調(diào)用AA.getInstance().method()

    class AA private Constructor(){
        fun method(){
            // ...  
        }
        companion object{
            @JvmStatic
            val instance: AA = AA()
        }
    }
    
  • 懶加載 --> 調(diào)用AA.getInstance().method()

    class AA private Constructor(){
        fun method(){
            // ...  
        }
        companion object{
            @JvmStatic
            val instance: AA by lazy { AA() }
        }
    }
    
  • 極簡(jiǎn)單例 (也是懶加載)--> 調(diào)用AA.INSTANCE.method().
    ps 在新版本里不能AA.INSTANCE, 直接AA.method()

    object AA{
        fun method(){
            // ...  
        }
    }
    

ps: 雖然 kotlin 的 lazy 文檔里提到 返回的是線程安全對(duì)象, 但我沒(méi)有測(cè)試(手動(dòng)滑稽)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,540評(píng)論 19 139
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類相關(guān)的語(yǔ)法,內(nèi)部類的語(yǔ)法,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法,線程的語(yǔ)...
    子非魚(yú)_t_閱讀 34,643評(píng)論 18 399
  • 前言 本文主要參考 那些年,我們一起寫(xiě)過(guò)的“單例模式”。 何為單例模式? 顧名思義,單例模式就是保證一個(gè)類僅有一個(gè)...
    tandeneck閱讀 2,623評(píng)論 1 8
  • 一. Java基礎(chǔ)部分.................................................
    wy_sure閱讀 4,011評(píng)論 0 11
  • 我們都知道,牛頓是在蘋(píng)果樹(shù)下發(fā)呆,被掉下來(lái)的蘋(píng)果砸到了腦袋,然后思考發(fā)現(xiàn)萬(wàn)有引力。 如果沒(méi)有發(fā)呆的機(jī)會(huì),牛頓能發(fā)現(xiàn)...
    三片阿司匹林閱讀 368評(píng)論 1 1

友情鏈接更多精彩內(nèi)容