在 Kotlin 中,synchronized(Singleton::class.java) 和 synchronized(Singleton::class) 的鎖對象本質(zhì)不同,這會導(dǎo)致同步行為差異。以下是詳細對比和結(jié)論:
- 本質(zhì)區(qū)別
表達式 鎖對象類型 實際鎖對象 線程同步范圍
synchronized(Singleton::class) Kotlin 的 KClass Singleton 的 KClass 實例 僅 Kotlin 側(cè)代碼
synchronized(Singleton::class.java) Java 的 Class 對象 Singleton 的 Java 類對象 全平臺(Java/Kotlin)
關(guān)鍵結(jié)論:
Singleton::class 獲取的是 Kotlin 的 KClass 反射對象,與 Java 的 Class 對象不是同一個實例。
Singleton::class.java 是通過 KClass.java 屬性顯式獲取 Java 的 Class 對象,與 Java 中的 Singleton.class 完全等價。 - 雙重校驗鎖的陷阱
若錯誤使用 synchronized(Singleton::class) 實現(xiàn)單例:
Kotlin
class Singleton private constructor() {
companion object {
@Volatile private var instance: Singleton? = null
fun getInstance(): Singleton {
return instance ?: synchronized(Singleton::class) { // 鎖的是 KClass,非 Java Class
instance ?: Singleton().also { instance = it }
}
}
}
}
問題表現(xiàn):
初始化多次:多個線程可能獲取不同的鎖對象(KClass 與 Java Class),導(dǎo)致同步失效。
與 Java 代碼不兼容:Java 代碼中若使用 synchronized(Singleton.class) 鎖住同一單例,會與 Kotlin 的 KClass 鎖形成兩把不同的鎖(破壞原子性)。
- 正確實踐
(1) 統(tǒng)一使用 Java 的 Class 對象
Kotlin
synchronized(Singleton::class.java) { // 明確鎖定 Java 類對象
// 雙重校驗邏輯
}
優(yōu)勢:
與 Java 的 synchronized(Singleton.class) 完全等價,確??缯Z言同步一致性。
兼容 JVM 的類鎖機制,避免類初始化沖突。
(2) 優(yōu)先使用 伴生對象實例 作為鎖
Kotlin
synchronized(this) { // this 指向 companion object 實例
// 雙重校驗邏輯
}
優(yōu)勢:
縮小鎖范圍,避免類鎖的全局競爭。
徹底消除與 Java 類鎖的潛在沖突。 - 字節(jié)碼驗證
編譯以下代碼:
Kotlin
fun testLock() {
synchronized(Singleton::class) { /* ... / }
synchronized(Singleton::class.java) { / ... */ }
}
反編譯后的 Java 代碼:
Java
public final void testLock() {
// synchronized(Singleton::class)
synchronized (Singleton.class) { // 實際鎖的是 Singleton 的 KClass 包裝類
// ...
}
// synchronized(Singleton::class.java)
synchronized (Singleton.class) { // 直接鎖 Java 的 Class 對象
// ...
}
}
陷阱:Kotlin 的 synchronized(Singleton::class) 實際編譯為 synchronized (Singleton.class),但此處的 Singleton.class 是 Kotlin 生成的 KClass 封裝類(如 Singleton.class 可能是 Singleton$Companion.class),而非原始 Java 類對象。
- 總結(jié)
場景 推薦鎖對象 原因
純 Kotlin 單例 synchronized(companion object) 縮小鎖粒度,避免類鎖副作用
跨 Java/Kotlin 的單例 synchronized(Singleton::class.java) 確保與 Java 類鎖一致,全平臺兼容
高頻初始化場景 優(yōu)先 Lazy 委托 避免手動管理鎖,代碼簡潔且線程安全
永遠避免 synchronized(Singleton::class),因其實際鎖對象可能不符合預(yù)期,破壞雙重校驗鎖的原子性。