kotlin .UninitializedPropertyAccessException, вызванное get Instance - PullRequest
0 голосов
/ 05 августа 2020

У меня есть следующий код для моего класса менеджера:

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

С следующий cra sh stack

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$1$1.invoke (MyOtherManager.kt:126)
  at my.package.MyOtherManager$launchThread$launched$1$1.invoke (MyOtherManager.kt:56)
  at my.package.MyOtherManagerKt$sam$i$java_lang_Runnable$0.run (Unknown Source:2)
  at java.lang.Thread.run (Thread.java:919)
  
  

Из подобных ошибок я понимаю, что я получаю экземпляр перед его установкой, но я не понимаю, как это возможно, если мое initialized логическое значение false по умолчанию, и в этом случае я устанавливаю переменную instance.

Что-то не так с тем, как я создаю экземпляр класса? Каково поведение моей строки 19, когда я вызываю synchronized, ждет ли она, чтобы выполнить ее сначала, прежде чем перейти к строке 26 (получение экземпляра), или существует риск получить экземпляр до того, как код внутри блока synchronized будет звонил?

1 Ответ

1 голос
/ 05 августа 2020

У этого кода есть несколько проблем.

Каково поведение моей строки 19, когда я вызываю synchronized, ждет ли она, чтобы выполнить ее, прежде чем перейти к строке 26 (получение экземпляра )

Эти строки кода не имеют принудительной связи. Нет ничего, что требовало бы принудительного вызова initialize(...) перед чтением свойства INSTANCE. Вам нужно убедиться, что вы звоните initialize перед каждый доступ к INSTANCE (или instance, если на то пошло).

Другая проблема заключается в том, что вы используете синхронизацию вот как-то странно. У вас есть блок synchronized, как будто вы ожидаете, что initiaize будет вызван из нескольких потоков, но он просто инициализирован с помощью Application. В этом нет необходимости, просто вызовите его один раз при запуске приложения.

Другая проблема заключается в том, что в зависимости от того, как именно вы это настраиваете, у вас может возникнуть проблема с поточной безопасностью. Если вы читаете это из другого потока, и инициализация instance не происходит до начала этого другого потока, инициализация может быть невидима для этого другого потока. Вы можете исправить это, сделав instance volatile.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...