Что такое ReadWriteLock?
ReadWriteLock — это интерфейс из пакета java.util.concurrent.locks, который оперирует парой связанных блокировок: одна для операций чтения, другая — для записи.
Основная идея: несколько потоков могут одновременно читать общий ресурс (shared lock), но запись требует эксклюзивного доступа (exclusive lock). Пока хотя бы один поток удерживает блокировку записи, ни один поток не может получить ни блокировку чтения, ни блокировку записи.
Реализация — ReentrantReadWriteLock:
Пример
ReadWriteLock rwLock = new ReentrantReadWriteLock();
Lock readLock = rwLock.readLock();
Lock writeLock = rwLock.writeLock();
// Чтение — множество потоков одновременно
readLock.lock();
try {
return cache.get(key); // shared reading
} finally {
readLock.unlock();
}
// Запись — эксклюзивный доступ
writeLock.lock();
try {
cache.put(key, value); // exclusive write
} finally {
writeLock.unlock();
}
Характеристики ReentrantReadWriteLock:
| Свойство | Значение |
|---|---|
| Максимум блокировок чтения | 65 535 |
| Максимум блокировок записи | 65 535 |
| Реентрабельность | Да, для обоих видов |
| Fairness | Настраивается (new ReentrantReadWriteLock(true)) |
| Понижение блокировки (write → read) | Да (захватить readLock, затем отпустить writeLock) |
| Повышение блокировки (read → write) | Нет (приведёт к deadlock) |
Понижение блокировки (lock downgrading):
Пример
writeLock.lock();
try {
updateData();
readLock.lock(); // Захватываем readLock, пока держим writeLock
} finally {
writeLock.unlock(); // Отпускаем writeLock — теперь только readLock
}
try {
return readData(); // Продолжаем читать под readLock
} finally {
readLock.unlock();
}
Когда использовать:
- Сценарии с преобладанием чтений над записями (кэши, конфигурации, справочники).
- Если записи преобладают или равны чтениям,
ReentrantReadWriteLockне даст преимущества — используйте обычныйReentrantLock. - Для ещё большей производительности при чтении рассмотрите
StampedLockс оптимистичным чтением (см. соответствующий вопрос).
Аналогия: ReadWriteLock — это правила библиотеки. Читать книгу могут несколько человек одновременно (они не мешают друг другу), но чтобы внести правку в книгу, нужно забрать её у всех читателей и работать в одиночку.
На собеседовании могут спросить: «Можно ли повысить readLock до writeLock?» Ответ: нет, нельзя — это приведёт к deadlock, потому что поток будет ждать освобождения readLock, который он сам удерживает. Для такого сценария используйте
StampedLock.tryConvertToWriteLock().