Какие типы локов существуют в Java и чем они отличаются от synchronized?
Что проверяют
Знаете ли вы, что даёт Lock сверх synchronized, и понимаете ли, зачем эта разница нужна.
Как отвечать
synchronized это ключевое слово: монитор объекта, вход и выход расставляет компилятор, блокировка снимается автоматически при выходе, в том числе через исключение. Просто и безопасно, но негибко: нельзя войти по таймауту, нельзя прервать ожидание, нельзя разделить чтение и запись.
Lock из java.util.concurrent.locks это интерфейс, дающий недостающее:
- ReentrantLock: то же взаимное исключение, но с
tryLock()без ожидания,tryLock(timeout),lockInterruptibly(), несколькими условиями черезnewCondition()и режимом честности; - ReentrantReadWriteLock: параллельные читатели, эксклюзивный писатель. Выигрывает при явном перевесе чтений;
- StampedLock: то же плюс оптимистичное чтение без блокировки с последующей проверкой. Быстрее, но не реентрантный и требует аккуратности.
Главная плата за гибкость: блокировку надо снимать самому, и единственный правильный способ это try/finally, иначе одно исключение подвешивает всех.
lock.lock();
try { ... } finally { lock.unlock(); }Практический выбор: synchronized по умолчанию, потому что его сложнее сломать; Lock, когда нужны таймаут, прерывание, несколько условий или разделение чтения и записи. И отдельно стоит помнить, что часто оба не нужны: атомарные классы и конкурентные коллекции решают задачу дешевле.
Где спотыкаются
Забывают unlock в finally.
Считают ReentrantLock быстрее: с Java 6 разница практически исчезла.
Берут ReadWriteLock, не замерив соотношение операций, и получают только накладные расходы.
Пытаются использовать StampedLock рекурсивно и ловят взаимную блокировку.