Что такое mutex и семафоры
Что проверяют
Понимаете ли вы синхронизацию в мире корутин. В Android общее состояние трогают не потоки напрямую, а корутины на разных диспетчерах, и блокирующий примитив в этом месте стоит дороже, чем кажется.
Как отвечать
Мьютекс это взаимное исключение, семафор это ограничение числа одновременных операций. В корутинах берут не synchronized, а Mutex с функцией withLock и Semaphore с withPermit из пакета kotlinx.coroutines.sync: они не блокируют поток, а приостанавливают корутину, поэтому ожидание не занимает поток из пула и не встаёт на главном.
private val mutex = Mutex()
private val limit = Semaphore(4)
suspend fun add(item: Item) = mutex.withLock { cache += item }
suspend fun load(id: String) = limit.withPermit { api.fetch(id) }Семафор здесь ограничивает параллельные загрузки, чтобы не открывать десятки соединений на мобильной сети. Дальше уместно сказать, что блокировка вообще не первый инструмент: состояние экрана держат в StateFlow и меняют через update, который сам повторяет попытку при конкурентной записи, а работу с данными замыкают на один диспетчер. Java-примитивы остаются для обычных потоков и чужих библиотек.
Где спотыкаются
Ставят synchronized вокруг вызова, который ходит в сеть или в базу. На главном потоке это подвисший кадр и риск ANR, на фоновом занятый поток из ограниченного пула. Внутри synchronized нельзя ещё и вызвать suspend-функцию: такой код просто не соберётся.
Считают корутинный Mutex реентерабельным. Повторный withLock внутри уже захваченного блока вешает корутину навсегда, и на устройстве это выглядит как экран, который не догрузился.
Лечат гонку блокировкой там, где хватило бы неизменяемых данных. Пока состояние копируется, а не правится на месте, синхронизировать нечего, и код остаётся читаемым.