kotlin—單例

kotlin—對象文件中,介紹了kotlin創(chuàng)建的對象的幾種方式,那么如何構建單例呢?
細心的朋友可能會發(fā)現簡單的對象聲明其實就是屬于餓漢式單例的實現方式,伴生對象看似是單例實則不是,除非使用@JvmStatic對其內部成員說明。
那么kotlin中怎么實現單例呢?

1、餓漢式

object StaticA {
    val x = 123
}

等價于java中的:

public class StaticA  {
  public static final StaticA  sInstance = new StaticA()
  private StaticA () {
  }
}

優(yōu)點:

  • 實現簡單
  • 線程安全,因為其在類加載時就進行了初始化,虛擬機內部保證其線程安全,保證對常量/靜態(tài)變量只進行一次初始化

缺點:

  • 在類加載時就創(chuàng)建了靜態(tài)對象,實際上可能不會用到,所以對資源來說是浪費了,同時時類的初始化變慢,性能上并不是很好

2、懶漢式

懶漢式就是懶加載,在使用時在進行初始化,其實現如下:

class SingleA {
    companion object {
        val sInstance by lazy(LazyThreadSafetyMode.NONE) {
            SingleA()
        }
    }
}

等價于java的:

public class SingleA  {
    private static sInstance;
    
    private SingleA() {
    }
    
    public static SingleA getInstance() {
        if (sInstance == null) {
            sInstance  = new SingleA()
        }
        return sInstance;
    }
}

優(yōu)點:

  • 延遲到使用時才進行初始化,提高了類加載的性能

缺點:

  • 非線程安全,多個線程同時訪問情況下,會創(chuàng)建多個實例

3、懶漢同步方法式

此方法是在第2中方式上在給房間加鎖來實現,如下:

class SingleB {
    companion object {
        var sInstance: SingleB? = null

        @Synchronized
        fun getInstance(): SingleB? {
            if (sInstance == null) {
                sInstance = SingleB()
            }
            return sInstance
        }
    }
}

等價于java的:

public class SingleB {
    private static SingleB sInstance;
  
    private SingleB() {
    }
    
    public static synchronized SingleB getInstance() {
        if (sInstance == null) {
            sInstance = new SingleB();
        }
        return sInstance;
    }
}

優(yōu)點:

  • 延遲到使用時才進行初始化,提高了類加載的性能
  • 對方法使用了同步鎖synchronized,保證了線程安全

缺點:

  • synchronized應用在方法上,所有是對整個方法加了鎖,所以性能上稍差

4、懶漢同步塊式(推薦)

與第3中的方式差不多,不同的是同步鎖應用在方法的內部語句塊中:

class SingleC {
    companion object {
        val sIntance by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
            SingleC()
        }
    }
}

等價于java的:

public class SingleC {
    private static SingleC sIntance;
    private SingleC() {
    }
    public static SingleC getInstance() {
        if (sIntance == null) {
            synchronized (SingleC.class) {
                if (sIntance == null) {
                    sIntance = new SingleC();
                }
            }
        }
        return sIntance;
    }
}

優(yōu)點:

  • 延遲到使用時才進行初始化,提高了類加載的性能
  • 在創(chuàng)建對象的語句塊中使用了同步鎖synchronized,保證線程安全的同時,降低了鎖的作用范圍

缺點:

  • 需要1-2次的空判斷

5、靜態(tài)內部類式(推薦)

靜態(tài)內部類的方式充分使用了語義的規(guī)則:

  • 靜態(tài)的語義規(guī)則——》使用到時才進行初始化,實現了懶加載
  • 靜態(tài)初始化是線程安全,線程的安全由虛擬機內部保證,保證靜態(tài)初始化時只被初始化一次

以下是kotlin靜態(tài)內部類的實現方式:

class SingleD {
    companion object {
        fun getInstance() = InstanceHelper.sSingle
    }
    object InstanceHelper {
        val sSingle = SingleD()
    }
}

等價于java的:

public class SingleD {
    private SingleD() {

    }
    private static class InstanceHelper {
        static SingleD sInstance = new SingleD();
    }
    public static SingleD getInstance() {
        return InstanceHelper.sInstance;
    }
}

優(yōu)點:

  • 延遲到使用時才進行初始化,提高了類加載的性能
  • 使用靜態(tài)初始化虛擬機保證線程安全的特性,實現了線程安全且鎖的性能在虛擬機內部實現性能較好

缺點:

  • 需要多一個額外的靜態(tài)內部類來輔助實現

6、總結

綜合上述的單例實現就數懶漢同步塊式和靜態(tài)內部類式的性能較好,那如何選擇呢?
從其實現的不同方式不難發(fā)現:

  • 懶漢同步塊式使用1-2兩次的判斷,所以執(zhí)行效率相比靜態(tài)內部類式較差,可以理解為空間優(yōu)先
  • 靜態(tài)內部類需要使用一個輔助類來實現,所以空間效率上比懶漢同步塊式差,可以理解為空間換執(zhí)行效率,執(zhí)行效率優(yōu)先

那我們該如何抉擇呢?
如果空間上沒有要求而執(zhí)行效率上有要求,可以考慮使用靜態(tài)內部類方式;如果空間上有要求而執(zhí)行效率有要求,則考慮使用懶漢同步塊式;如果空間和執(zhí)行效率都有要求,需要權衡更需要那種方式而另一種則不得不做出犧牲,比較魚和熊掌不可兼得;如果空間和執(zhí)行效率都沒有要求,就看個人喜好了。

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

相關閱讀更多精彩內容

  • 單例設計模式有著非常廣泛的應用,而平時我們接觸的都是些Java的實現方式,關于Kotlin的單例模式則很少被提及,...
    呱呱_閱讀 1,660評論 3 5
  • 作者已經搬遷去隔壁網站,也歡迎大家關注我們的寫作團隊:天星技術團隊。 題外話 上一次被人說文章名字取得不霸氣,于是...
    點先生在這閱讀 657評論 1 1
  • 最近在寫項目的同時也用到了單例模式,kotlin的單例還不是很會寫,現在就總結下java寫法對應的kotlin是如...
    李die喋閱讀 478評論 0 2
  • Kotlin 的單例模式(5種) Kotlin 的5種單例模式: 餓漢式 懶漢式 線程安全的懶漢式 雙重校驗鎖式 ...
    眼中有碼閱讀 1,802評論 0 5
  • 5種常見單例 餓漢式 懶漢式 同步鎖式 雙重檢查式(double-check) 內部類式 1. 餓漢式 優(yōu)點:簡單...
    dashixun閱讀 438評論 0 0

友情鏈接更多精彩內容