class Notification(val context: Context, title: String, message: String) {
private val channelID = "TestMessages"
companion object ID {
var s_notificationID = -1
}
init {
var notificationID = -1
synchronized(s_notificationID) {
if (++s_notificationID == 0)
createNotificationChannel()
notificationID = s_notificationID
}
以上是从两个线程同时调用的。 createNotificationChannel()
中的断点清楚地表明,有时s_notificationID
等于 1。但是,如果我改变
synchronized(s_notificationID)
至 synchronized(ID)
那么它似乎锁定得很好。synchronized() 是否不锁定基本类型?如果是这样,为什么要编译?
最佳答案
查看生成的 JVM 字节码表明 ID
例子看起来像
synchronized(ID) { ... }
这是你所期望的。然而,s_notificationID
示例看起来更像synchronized(Integer.valueOf(s_notificationID)) { ... }
在 Java 中,我们只能同步对象,而不能同步原语。 Kotlin 基本上消除了这种区别,但看起来您已经找到了一个实现仍然渗透的地方。自 s_notificationID
是 int
就 JVM 而言(因此,不是对象)而是 synchronized
期望一个对象,Kotlin 足够“聪明”,可以将值包装在 Integer.valueOf
中一经请求。对您来说不幸的是,这会产生非常不一致的结果,becauseThis method will always cache values in the range -128 to 127, inclusive, and may cache other values outside of this range.
因此,对于较小的数字,这可以保证锁定内存中您无法控制的某些缓存对象。对于较大的对象,它可能是一个新对象(因此总是未锁定),或者它可能会再次出现在您手中的缓存对象上。
这里的教训似乎是:不要同步原始类型。
关于kotlin - Kotlin synchronized() 是否不锁定基本类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68423781/