Доводилось ли работать с конкурентными коллекциями и какие они бывают
Что проверяют
Понимаете ли вы, почему обычные ArrayList и HashMap ломаются при доступе из нескольких потоков и чем разные коллекции платят за безопасность. На Android следом часто спрашивают, как вы решаете ту же задачу в корутинах.
Как отвечать
Начните с опыта: где был общий доступ из нескольких потоков (кэш в памяти, очередь событий аналитики, список слушателей) и что выбрали. Если в продакшене не пришлось, скажите честно и объясните, что взяли бы. Основные типы из java.util.concurrent:
ConcurrentHashMap: чтение без блокировок, запись блокирует одну корзину. АтомарныеputIfAbsent,computeIfAbsent,merge. Не принимаетnullни в ключах, ни в значениях;CopyOnWriteArrayList: при каждой записи копирует массив, чтение идёт без блокировок. Хорош для слушателей, где читают часто, а меняют редко;- очереди:
ConcurrentLinkedQueueнеблокирующая,LinkedBlockingQueueиArrayBlockingQueueс блокирующимиput/takeдля схемы производитель и потребитель; - обёртки:
Collections.synchronizedListставит один монитор на всю коллекцию, а итерацию всё равно оборачивают вsynchronizedвручную.
Итераторы конкурентных коллекций слабо согласованы: не бросают ConcurrentModificationException, но могут не увидеть свежих изменений. В Kotlin на корутинах общий изменяемый список часто заменяют на MutableStateFlow с атомарным update {}, Mutex или Channel: блокирующая очередь там займёт поток диспетчера.
Где спотыкаются
Рассказывают про сегменты в ConcurrentHashMap. Это устройство старых версий Java, сейчас запись блокирует отдельную корзину и опирается на CAS.
Считают, что потокобезопасная коллекция делает атомарной любую логику. if (!map.containsKey(k)) map.put(k, v) остаётся гонкой, нужен computeIfAbsent. А Kotlin-расширение getOrPut на ConcurrentMap может вызвать лямбду несколько раз.
Берут CopyOnWriteArrayList туда, куда постоянно пишут, и получают копию массива на каждое добавление.