0Pricing
Java Academy · Урок

StampedLock и оптимистичное чтение

Применяйте режим оптимистичного чтения StampedLock для высокопроизводительных нагрузок, преимущественно связанных с чтением.

«StampedLock и оптимистичное чтение» — бесплатный урок Java Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Java Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Java Academy содержит 4 уроков всего.

Что такое StampedLock

Появившийся в Java 8 класс StampedLock расширяет концепции ReadWriteLock дополнительным режимом оптимистичного чтения. Операции возвращают длинную метку, которая используется для освобождения блокировки или проверки оптимистичного чтения.

import java.util.concurrent.locks.*;

StampedLock sl = new StampedLock();

// Exclusive write:
long stamp = sl.writeLock();
try {
    // write data
} finally {
    sl.unlockWrite(stamp);
}

// Shared read:
stamp = sl.readLock();
try {
    // read data
} finally {
    sl.unlockRead(stamp);
}

Режим оптимистичного чтения

При оптимистичном чтении блокировка не захватывается — вместо этого просто получается метка. После чтения проверьте метку. Если проверка не пройдена (писатель успел изменить данные), перейдите к настоящей блокировке чтения:

StampedLock sl2 = new StampedLock();
double x = 0, y = 0;

// Try optimistic read first:
long stamp = sl2.tryOptimisticRead();
double localX = x, localY = y; // read values

if (!sl2.validate(stamp)) {
    // A write occurred — fall back to read lock
    stamp = sl2.readLock();
    try {
        localX = x;
        localY = y;
    } finally {
        sl2.unlockRead(stamp);
    }
}
// use localX and localY

Полный пример двумерной точки

Классический пример StampedLock — двумерная точка с оптимистичным чтением:

class Point {
    private double x, y;
    private final StampedLock lock = new StampedLock();
    
    void move(double dx, double dy) {
        long stamp = lock.writeLock();
        try { x += dx; y += dy; }
        finally { lock.unlockWrite(stamp); }
    }
    
    double distanceFromOrigin() {
        long stamp = lock.tryOptimisticRead();
        double cx = x, cy = y;
        if (!lock.validate(stamp)) {
            stamp = lock.readLock();
            try { cx = x; cy = y; }
            finally { lock.unlockRead(stamp); }
        }
        return Math.sqrt(cx * cx + cy * cy);
    }
}

Преобразование блокировки

StampedLock поддерживает преобразование между режимами блокировки:

StampedLock sl3 = new StampedLock();

// Read → Write upgrade attempt:
long readStamp = sl3.readLock();
long writeStamp = sl3.tryConvertToWriteLock(readStamp);
if (writeStamp != 0) {
    // Successfully upgraded!
    // ... write ...
    sl3.unlockWrite(writeStamp);
} else {
    // Upgrade failed — release read and reacquire write
    sl3.unlockRead(readStamp);
    writeStamp = sl3.writeLock();
    // ... write ...
    sl3.unlockWrite(writeStamp);
}

Когда оптимистичное чтение наиболее полезно

Оптимистичное чтение особенно эффективно, если:

  • операции чтения выполняются намного чаще операций записи;
  • снимок данных помещается в несколько локальных переменных (без создания объекта);
  • конкуренция при записи невысока (проверка редко завершается неудачей).

Если записи выполняются часто, оптимистичные чтения постоянно переходят к полноценным блокировкам чтения и не дают преимуществ.

StampedLock и ReadWriteLock

Главные различия:

  • StampedLock: добавляет оптимистичное чтение; НЕ допускает повторного захвата; не поддерживает условные переменные
  • ReentrantReadWriteLock: допускает повторный захват; поддерживает условные переменные; не имеет оптимистичного режима

StampedLock работает быстрее при низкой конкуренции записи. ReentrantReadWriteLock безопаснее и предоставляет больше возможностей.

StampedLock НЕ допускает повторного захвата

В отличие от ReentrantLock, StampedLock НЕ допускает повторного захвата. Поток, пытающийся получить уже удерживаемый им режим, попадёт во взаимную блокировку:

StampedLock sl4 = new StampedLock();
long s1 = sl4.readLock();
// DO NOT: sl4.readLock() again — deadlocks with non-reentrant!

tryWriteLock и tryReadLock

Неблокирующие попытки захвата возвращают 0 при неудаче:

StampedLock sl5 = new StampedLock();

long stamp = sl5.tryWriteLock();
if (stamp != 0) {
    try {
        System.out.println("Got write lock");
    } finally {
        sl5.unlockWrite(stamp);
    }
} else {
    System.out.println("Write lock unavailable");
}

Использование в качестве ReadWriteLock

StampedLock может вернуть представление в виде стандартного ReadWriteLock для совместимости:

StampedLock sl6 = new StampedLock();
Lock readLock  = sl6.asReadLock();
Lock writeLock = sl6.asWriteLock();
ReadWriteLock rwView = sl6.asReadWriteLock();
// These provide standard Lock interface without optimistic mode

Представление о сравнении производительности

Результаты измерений обычно показывают:

  • сильное преобладание чтения (99% чтений): StampedLock > ReadWriteLock > synchronized
  • смешанная нагрузка (70% чтений): ReadWriteLock ≈ StampedLock
  • преобладание записи: чаще выигрывают synchronized или ReentrantLock (меньше издержек)

Перед оптимизацией всегда измеряйте производительность на реалистичных рабочих нагрузках.

Недействительность метки после освобождения

После освобождения блокировки с помощью метки эта метка становится недействительной. Использование старой метки после освобождения приводит к неопределённому поведению — всегда получайте новую метку при каждом захвате блокировки.

StampedLock sl7 = new StampedLock();
long stamp = sl7.writeLock();
sl7.unlockWrite(stamp);
// stamp is now invalid — don't use it:
// sl7.unlockWrite(stamp); // throws IllegalMonitorStateException or corrupts state

Быстрая проверка

Оптимистичное чтение с помощью tryOptimisticRead() и последующая проверка validate(stamp) возвращают false. Что код должен сделать дальше?

Итоги: StampedLock

Главное:

  • Три режима: оптимистичное чтение (без блокировки), блокировка чтения и блокировка записи
  • tryOptimisticRead() + validate() — попытка чтения без затрат на захват блокировки
  • При неудачной проверке переходите к блокировке чтения
  • Повторный захват НЕ поддерживается — повторный захват тем же потоком может привести к взаимной блокировке
  • Условные переменные не поддерживаются — при необходимости используйте ReentrantReadWriteLock

Часто задаваемые вопросы

Урок «StampedLock и оптимистичное чтение» бесплатный?

Да — полный текст урока «StampedLock и оптимистичное чтение» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Java Academy, подпишись на CoddyKit PRO. Курс Java Academy содержит 4 уроков всего.

Чему я научусь в уроке «StampedLock и оптимистичное чтение»?

Применяйте режим оптимистичного чтения StampedLock для высокопроизводительных нагрузок, преимущественно связанных с чтением. Ты практикуешь Java Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Java Academy?

Предыдущий опыт не требуется. Java Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.

Сколько времени занимает урок «StampedLock и оптимистичное чтение»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Java Academy?

Да. Каждый урок Java Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. ReentrantLock и synchronized
  2. ReadWriteLock для сценариев чтения и записи
  3. Атомарные переменные: обновления без блокировок
  4. StampedLock и оптимистичное чтение
← Назад к Java Academy