代码之家  ›  专栏  ›  技术社区  ›  Bass

@Volatile lateinit变量可以在Kotlin中使用DCL模式进行原子初始化吗?

  •  1
  • Bass  · 技术社区  · 7 月前

    考虑以下用Kotlin编写的DCL示例:

    @Volatile
    private var property: String? = null
    
    private val lock = ReentrantLock()
    
    fun singletonValue(): String {
        if (property == null) {
            lock.withLock {
                if (property == null) {
                    property = "Hello World"
                }
            }
        }
        return property!!
    }
    

    这与20年前讨论的Java版本几乎相同,当时Java内存模型随着从Java 1.4到Java 5的过渡而得到了纠正。话虽如此,我完全相信上述代码片段在JVM上运行时会正确运行。

    现在,让我们使用a lateinit var 相反:

    @Volatile
    private lateinit var property: String
    
    private val lock = ReentrantLock()
    
    fun singletonValue(): String {
        if (!::property.isInitialized) {
            lock.withLock {
                if (!::property.isInitialized) {
                    property = "Hello World"
                }
            }
        }
        return property
    }
    

    它在语义上与原始示例等效吗?它是否保持相同的原子性和可见性保证?

    1 回复  |  直到 7 月前
        1
  •  1
  •   Sweeper    7 月前

    这两个代码片段编译成几乎相同的字节码。 lateinit 属性只是被编译成常规的Java字段,以及 isInitialized 基本上是一个空检查。

    唯一的区别是最后一个 return 声明。接触不熟悉的人 lateinit 财产将抛出 UninitializedPropertyAccessException ,而 property!! 会扔一个 NullPointerException 什么时候 property 为空。当然,这种差异与相同的线程安全保证是否成立无关。

    也就是说,目前还没有Kotlin/JVM规范,Kotlin/Core规范也没有提到任何关于并发性的内容。所以 严格来说 ,很难保证Kotlin代码将如何编译成字节码。