Будет ли работать volatile для инкремента переменной в многопоточном окружении
Что проверяют
Различаете ли вы видимость и атомарность: два свойства, которые кандидаты постоянно склеивают. Следом спрашивают, чем заменить volatile, и как та же задача решается в корутинах.
Как отвечать
Коротко: нет, не будет. volatile в Java и @Volatile в Kotlin дают две гарантии модели памяти: запись сразу видна другим потокам, и между записью и последующим чтением есть отношение happens-before, то есть операции не переставляются через эту границу. Атомарности составной операции они не дают.
counter++ это три шага: прочитать, прибавить, записать. Два потока читают 5, оба пишут 6, одно увеличение пропало. Запустите 100 корутин на Dispatchers.Default, каждая делает count++ тысячу раз, и итог почти наверняка окажется меньше 100 000.
Что использовать вместо:
AtomicIntegerиAtomicLong:incrementAndGet()работает через CAS без блокировок, выбор по умолчанию для счётчика;LongAdder: при сильной конкуренции за один счётчик быстрее атомика, на Android доступен с API 24;synchronizedили@Synchronized: когда нужно атомарно изменить несколько полей сразу;Mutexиз kotlinx.coroutines:mutex.withLock { }не блокирует поток, а приостанавливает корутину. Внутриsynchronizedточку приостановки поставить нельзя, компилятор это запрещает. Альтернатива:Dispatchers.Default.limitedParallelism(1).
Где volatile уместен: флаг, который пишет один поток, а читают остальные (isRunning, isCancelled), и поле в double-checked locking.
Где спотыкаются
Пишут counter.set(counter.get() + 1) на AtomicInteger и считают это безопасным. Между get и set вклинивается другой поток, нужны incrementAndGet или updateAndGet.
Защищают данные synchronized на разных объектах: в одном методе блокировка на this, в другом на отдельном lock. Взаимного исключения при этом нет.
Считают атомарным _state.value = _state.value + 1 у MutableStateFlow. Это то же чтение и запись по отдельности, под нагрузкой обновления теряются. Для изменения на основе текущего значения есть update { it + 1 }, который повторяет попытку через CAS.