Следите за новинками
в нашем Telegram канале. Жми, чтобы подписаться:)
⊗ktSpSyInr 168 of 299 menu
◀ ▶

Введение в синхронизацию в Kotlin

Несколько корутин могут одновременно читать и менять одну переменную. Каждый шаг "прочитать - прибавить - записать" выглядит атомарным только в исходнике: между чтением и записью другая задача успевает сделать то же самое, и часть приращений теряется.

Гонка проявляется на общем счетчике, когда две фоновые корутины много раз увеличивают одно число. После join итог часто меньше ожидаемой суммы шагов, хотя каждая итерация выглядит простой.

Проверка на двух задачах по тысяче приращений без защиты обычно дает число ниже 2000:

import kotlinx.coroutines.joinAll import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking fun main() { runBlocking { var hits = 0 val jobs = List(2) { launch { repeat(1000) { hits++ } } } joinAll(*jobs.toTypedArray()) println(hits) } }

Mutex из kotlinx.coroutines.sync держит очередь: в критический участок входит одна корутина, остальные ждут на приостановке, пока замок не освободится. Короткое приращение под замком выглядит так:

import kotlinx.coroutines.joinAll import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import kotlinx.coroutines.sync.Mutex fun main() { runBlocking { var hits = 0 val guard = Mutex() val jobs = List(2) { launch { repeat(1000) { guard.lock() try { hits++ } finally { guard.unlock() } } } } joinAll(*jobs.toTypedArray()) println(hits) } }

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

← →
↑
Мы используем cookie для работы сайта, аналитики и персонализации. Обработка данных происходит согласно Политике конфиденциальности.
принять все настроить отклонить