Какие классы из java.util.concurrent используются для оптимистичной и пессимистичной блокировок
Что проверяют
Различаете ли вы две стратегии: захватить ресурс заранее или работать без блокировки и проверить конфликт в конце. Следом часто спрашивают, как устроен CAS и что такое проблема ABA.
Как отвечать
Пессимистичная блокировка захватывает ресурс до работы с ним, остальные потоки ждут:
ReentrantLock: явная реентерабельная блокировка сtryLockпо таймауту, прерываемымlockInterruptiblyи несколькимиCondition, есть справедливый режим;ReentrantReadWriteLock: тоже пессимистичная, просто разделяет чтение и запись. Читатели работают параллельно, писатель получает эксклюзивный доступ;Semaphore: не блокировка в строгом смысле, а ограничение числа одновременных владельцев разрешений.
К этой же стратегии относится synchronized, хотя он часть языка, а не пакета.
Оптимистичная стратегия ничего не блокирует, а при конфликте повторяет попытку:
- атомарные классы из
java.util.concurrent.atomic:AtomicInteger,AtomicLong,AtomicReference. Основа этоcompareAndSet: записать новое значение, только если текущее равно ожидаемому.updateAndGetиaccumulateAndGetкрутят этот цикл за вас; LongAdder: счётчик под высокой конкуренцией, раскладывает обновления по ячейкам и суммирует при чтении;AtomicStampedReference: CAS со счётчиком версии, защищает от ABA;StampedLock: совмещает оба подхода.tryOptimisticRead()выдаёт штамп без блокировки, после чтенияvalidate(stamp)проверяет, не было ли записи, и при неудаче чтение повторяют подreadLock().
Ориентир для выбора: при редких конфликтах оптимистичный подход быстрее, при частых он тратит CPU на повторы, и блокировка выигрывает.
Где спотыкаются
Называют ReentrantReadWriteLock оптимистичной блокировкой. Параллельное чтение не делает её оптимистичной: запись всё равно ждёт.
Отвечают про @Version в JPA. Это тоже оптимистичная блокировка, но для строк в базе, а вопрос про память внутри JVM: упомянуть можно, подменять ответ нельзя.
Забывают, что StampedLock не реентерабельный и не поддерживает Condition. Повторный захват записи в том же потоке приводит к взаимоблокировке.