kotlin.UninitializedPropertyAccessException 由获取实例引起

kotlin.UninitializedPropertyAccessException caused by get Instance

我的经理有以下代码 class :

11 class MyManager private constructor(application: Application) {
12    companion object {
13        val TAG = MyManager::class.java.simpleName
14
15        private val initialized = AtomicBoolean(false)
16        private lateinit var instance: MyManager
17
18        fun initialize(application: Application) {
19            synchronized(initialized) {
20                if (!initialized.getAndSet(true)) {
21                    instance = MyManager(application)
22                }
23            }
24        }
25
26        val INSTANCE get() = instance
27    }

我的一些应用程序用户崩溃了
 val INSTANCE get() = instance

具有以下崩溃堆栈

kotlin.UninitializedPropertyAccessException: 
  at my.package.MyManager$Companion.getINSTANCE (MyManager.kt:26)
  at my.package.MyOtherManager.systemInitialization (MyOtherManager.kt:585)
  at my.package.MyOtherManager.doRun (MyOtherManager.kt:433)
  at my.package.MyOtherManager.access$doRun (MyOtherManager.kt:56)
  at my.package.MyOtherManager$launchThread$launched.invoke (MyOtherManager.kt:126)
  at my.package.MyOtherManager$launchThread$launched.invoke (MyOtherManager.kt:56)
  at my.package.MyOtherManagerKt$sam$i$java_lang_Runnable[=13=].run (Unknown Source:2)
  at java.lang.Thread.run (Thread.java:919)
  
  

我从类似的错误中了解到,我在设置它之前获取实例,但我不知道如果我的 initialized 布尔值默认为 false 并且我正在设置 instance 视情况而定。

我实例化 Class 的方式有问题吗? 我的第 19 行的行为是什么,当我调用 synchronized 时,它是先等待执行它再转到第 26 行(获取实例)还是存在在 [=16 中的代码之前获取实例的风险=] 阻止被调用?

这段代码有一些问题。

What's the behaviour for my line 19, when I call synchronized, does it wait to execute it first before going to line 26 (getting the instance)

这几行代码没有强制关系。在 INSTANCE 属性 的任何读取之前调用 initialize(...) 没有任何强制要求。您需要确保在 每次 访问 INSTANCE(或 instance)之前调用 initialize

另一个问题是你在这里使用同步有点奇怪。你有一个 synchronized 块,就好像你希望从多个线程调用 initiaize 一样,但它只是用 Application 初始化的。这不是必需的,只需在应用程序启动时调用一次即可。

另一个问题是,根据您的具体设置方式,您可能会遇到 thread-safety 问题。如果您正在从另一个线程读取此内容,并且 instance 的初始化不是 happens-before 另一个线程的开始,则该初始化可能对另一个线程不可见。您可以通过 instance volatile.

来解决这个问题