Intereting Posts
Как вызвать функцию после задержки в Котлине? Как я могу автоматически присвоить переменную переменной по типу в реальном шаблоне? Получите дополнительную строку от активности Kotlin Android: Kotlin с кинжалом Свойства бина, не равные нулю при инициализации, становятся нулевыми при вызове метода @Transactional Объединение Rx Singles в наблюдаемые рекурсивно Как я могу запускать заливки Kotlin-Script (* .kts) из Gradle? Программно сделать изображениеView видимым / невидимым с помощью переменной В чем причина использования суффикса «Kt» в классах Котлина? Настройка кинжала 2 при условии модернизации Веб-программирование Kotlin без использования Intelli-J Ultimate? Случайное переопределение: следующие объявления имеют одну и ту же подпись JVM Как установить конфигурации package.json с помощью kotlin-frontend-plugin Поддерживается ли kapt в maven? Как получить завершение кода IntelliJ IDEA для импорта статических методов Java в качестве функций верхнего уровня Kotlin?

Безопасность локальных переменных потоков Kotlin

Поэтому я писал единичный тест для тестирования многопоточности, и я хочу знать, будет ли этот код работать так, как я ожидал.

fun testNumbers() { var firstNumber: Int? = null var secondNumber: Int? = null val startLatch = CountDownLatch(2) val exec = Executors.newFixedThreadPool(2) exec.submit({ startLatch.countDown() startLatch.await() firstNumber = StuffDoer.makeNumber() }) exec.submit({ startLatch.countDown() startLatch.await() secondNumber = StuffDoer().makeNumber() }) while (firstNumber == null || secondNumber == null) { Thread.sleep(1) } } 

В частности, этот метод гарантированно завершен? firstNumber и secondNumber не являются volatile так это значит, что результаты, установленные в этих значениях из потоков exec никогда не будут видны потоком, выполняющим тест? Вы не можете применять volatile к локальным переменным, так что практически говоря, для меня не было бы смысла, что вы не можете сделать переменные функции локальными, если это может понадобиться.

(Я добавил Java как тег, потому что, по-видимому, основной вопрос в Java такой же).

При компиляции с компилятором Kotlin 1.1 RC локальные переменные в вашем коде хранятся в ObjectRef s, которые затем используются в lambdas.

Вы можете проверить, какой фрагмент кода скомпилирован, используя средство просмотра байт-кодов Kotlin .

ObjectRef сохраняет ссылку в энергонезависимом поле , поэтому действительно нет гарантии, что программа завершится.

Более ранние версии Kotlin использовали поле volatile в классах Ref , но это была недокументированная деталь реализации (то есть не на что полагаться), которая в конечном итоге была изменена в Kotlin 1.1. См. Эту тему для мотивации за неизменяемыми захваченными переменными.


Как сказано в описании проблемы ,

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

Чтобы правильно выполнить синхронизацию вашей .get() программы, достаточно вызвать .get() в двух экземплярах Future возвращенных из exec.submit { } , так как Future обеспечивает выполнение – перед гарантиями:

Действия, предпринятые асинхронным вычислением, представленными Future.get() Future перед последующим извлечением результата через Future.get() в другом потоке.

 val f1 = exec.submit { /* ... */ } val f2 = exec.submit { /* ... */ } f1.get() f2.get() // Both assignments made in the submitted tasks are visible now assert(firstNumber != null) assert(secondNumber != null)