Что такое StampedLock и чем он отличается от ReentrantReadWriteLock?
StampedLock — это блокировка из Java 8, которая поддерживает три режима доступа: запись, чтение и оптимистичное чтение. Обеспечивает более высокую производительность по сравнению с ReentrantReadWriteLock при преобладании операций чтения.
Три режима:
- Запись (write lock) — эксклюзивная блокировка.
- Чтение (read lock) — разделяемая блокировка.
- Оптимистичное чтение (optimistic read) — неблокирующее. Возвращается «штамп» (stamp), который проверяется на валидность. Если за время чтения произошла запись — штамп невалиден, нужно повторить чтение.
Код: StampedLock с оптимистичным чтением
class Point {
private double x, y;
private final StampedLock lock = new StampedLock();
// Запись
void move(double deltaX, double deltaY) {
long stamp = lock.writeLock();
try {
x += deltaX;
y += deltaY;
} finally {
lock.unlockWrite(stamp);
}
}
// Оптимистичное чтение — самый производительный способ
double distanceFromOrigin() {
long stamp = lock.tryOptimisticRead(); // Не блокирует!
double currentX = x, currentY = y; // Читаем данные
if (!lock.validate(stamp)) { // Проверяем: была ли запись?
// Если была — переходим к пессимистичному чтению
stamp = lock.readLock();
try {
currentX = x;
currentY = y;
} finally {
lock.unlockRead(stamp);
}
}
return Math.sqrt(currentX * currentX + currentY * currentY);
}
}
Сравнение с ReentrantReadWriteLock:
| Характеристика | ReentrantReadWriteLock |
StampedLock |
|---|---|---|
| Оптимистичное чтение | Нет | Да |
| Реентрабельность | Да | Нет |
Условия (Condition) |
Да | Нет |
| Fairness policy | Да | Нет |
| Конвертация блокировок | Нет | Да (read -> write, optimistic -> read) |
| Производительность чтения | Хорошая | Отличная (с optimistic read) |
Конвертация блокировок:
Код: повышение блокировки чтения до записи
long stamp = lock.readLock();
try {
while (x == 0.0) {
long writeStamp = lock.tryConvertToWriteLock(stamp);
if (writeStamp != 0L) {
stamp = writeStamp;
x = 1.0;
break;
} else {
lock.unlockRead(stamp);
stamp = lock.writeLock();
}
}
} finally {
lock.unlock(stamp);
}
Ключевые особенности:
- Не реентрабелен — повторный захват из того же потока приведёт к deadlock.
- Оптимистичное чтение — это не блокировка, а «снимок» состояния. Валидация обязательна.
- Не реализует интерфейс
Lock— собственный API на основе штампов (long stamp). - Лучше всего подходит для коротких критических секций с преобладанием чтения.
Частые ошибки:
- Забытый
finally— штамп нужно передавать приunlock, безfinally— вечная блокировка. - Оптимистичное чтение для длинных операций — частые повторения могут быть дороже обычной блокировки.
- Реентрабельный захват — deadlock без явной ошибки.
- Неверный штамп в
unlock—IllegalMonitorStateException.
Аналогия:
StampedLockс оптимистичным чтением — это как чтение расписания на вокзале. Вы подходите, читаете время (optimistic read), а затем проверяете, не перевернулся ли табло (validate). Если перевернулось — читаете заново. Если нет — используете данные. Это быстрее, чем ждать в очереди у окошка кассы (pessimistic read lock).
На собеседовании ключевой вопрос: «Когда
StampedLockлучшеReentrantReadWriteLock?» Ответ: когда соотношение чтений к записям высокое (>10:1) и критические секции короткие. Главное ограничение — отсутствие реентрабельности.