Ответ
Да, синхронизация нужна, даже при работе в Main Dispatcher. Хотя Main Dispatcher однопоточный, корутины могут приостанавливаться (например, при вызове delay()), что приводит к race condition при изменении общих переменных.
Пример:
var counter = 0
fun main() = runBlocking {
repeat(100) {
launch(Dispatchers.Main) {
val temp = counter
delay(10) // точка приостановки
counter = temp + 1
}
}
delay(1000)
println(counter) // Может быть меньше 100
}
Решение - использовать атомарные типы или мьютексы:
val counter = AtomicInteger(0)
// или
val mutex = Mutex()
var counter = 0
// В корутине:
mutex.withLock {
counter++
}