Может ли отсутствие синхронизации привести к остановке программы
Что проверяют
Понимаете ли вы, что «остановка» бывает двух видов: падение с исключением и зависание, когда процесс жив, но ничего не делает. Следом обычно просят показать, чем это закончится на Android: крашем или ANR.
Как отвечать
Да, может, и по нескольким сценариям:
- гонка на коллекции: два потока пишут в один
ArrayListилиHashMap. Итератор ловитConcurrentModificationException, а одновременное расширение массива даётArrayIndexOutOfBoundsExceptionили потерянные элементы. Необработанное исключение в любом потоке роняет весь процесс; - несогласованное состояние: один поток обнулил поле, другой успел его проверить и через миг получил
NullPointerException. Проверка и действие без блокировки не атомарны; - видимость: флаг
isRunningбез@Volatileможет не дойти до другого потока, и циклwhile (isRunning)в фоне не остановится никогда; - ANR: главный поток ждёт монитор, который держит фоновый поток с сетевым запросом. Если UI не отвечает на ввод около пяти секунд, система показывает диалог «Приложение не отвечает».
Защита по уровням: неизменяемые данные и один владелец состояния, затем атомики (AtomicInteger, AtomicReference) и потокобезопасные коллекции (ConcurrentHashMap, CopyOnWriteArrayList), затем явные блокировки. В корутинах вместо synchronized берут Mutex из kotlinx.coroutines.sync: внутри него можно вызывать suspend-функции, а поток не блокируется. Состояние экрана удобно держать в MutableStateFlow и менять через update {}, это атомарная операция.
Где спотыкаются
Говорят только про гонки и забывают обратную сторону: избыточная синхронизация тоже останавливает программу. Две блокировки, взятые в разном порядке, дают взаимную блокировку, и приложение зависает без единой строки в логе.
Считают корутины потокобезопасными по умолчанию. Dispatchers.Default и Dispatchers.IO это пулы потоков, и counter++ из тысячи корутин на них даст неверный результат.
Оборачивают список в Collections.synchronizedList и думают, что проблема решена. Отдельные вызовы защищены, а обход через for всё равно нужно синхронизировать вручную.