JavaRush /Курсы /JSP & Servlets /Java Locks: блокировка доступа к ресурсам

Java Locks: блокировка доступа к ресурсам

JSP & Servlets
19 уровень , 7 лекция
Открыта

ReentrantLock

Condition — применение условий в блокировках позволяет добиться контроля над управлением доступа к потокам. Условие блокировки представлет собой объект интерфейса Condition из пакета java.util.concurrent.locks. Применение объектов Condition во многом аналогично использованию методов wait/notify/notifyAll класса Object, которые были рассмотрены в одной из прошлых тем.

Lock — интерфейс из lock framework, предоставляющий гибкий подход по ограничению доступа к ресурсам/блокам по сравнению с synchronized. При использовании нескольких локов порядок их освобождения может быть произвольный, плюс его также можно настроить. Еще имеется возможность обработать ситуацию, когда лок уже захвачен.

ReentrantLock — одна из реализаций интерфейса Lock — класс ReenterantLock. Он позволяет одному и тому же потоку вызывать метод lock, даже если он его вызывал ранее, без освобождения блокировки.

У класса ReentrantLock, кроме методов интерфейса Lock, есть фабричный метод newCondition(). Этот метод возвращает объект Condition, который позволяет добавить текущий поток в wait set данного объекта Condition.


private final Lock R_LOCK = ReentrantLock();
R_LOCK.lock();
try {
   //тут происходят какие-то действия
} finally {
   R_LOCK.unlock();
}

ReadWriteLock — интерфейс для создания read/write локов. Локи необычайно полезны, когда в системе много операций чтения и мало операций записи.

ReentrantReadWriteLock — используется в многопоточных сервисах и кешах, имеют хороший прирост производительности по сравнению с блоками synchronized. По сути, класс работает в 2-х взаимоисключающих режимах: много читателей читают данные в параллель и когда только 1 райтер пишет данные.

ReentrantReadWriteLock.ReadLock — read lock для reader'ов, получаемый через readWriteLock.readLock().

ReentrantReadWriteLock.WriteLock — write lock для writer'ов, получаемый через readWriteLock.writeLock().

Synchronizer

AbstractOwnableSynchronizer — базовый класс, который отвечает за построение механизмов синхронизации. Содержит геттер/сеттер для запоминания и чтения эксклюзивного потока, который может работать с вашими данными.

AbstractQueuedSynchronizer — базовый класс для механизма синхронизации в FutureTask, CountDownLatch, Semaphore, ReentrantLock, ReentrantReadWriteLock. Также он применяется при создании новых механизмов синхронизации, полагающихся на одиночное и атомарное значение int.

AbstractQueuedLongSynchronizer — разновидность AbstractQueuedSynchronizer, поддерживающая атомарное значение long.

Комментарии (4)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Anonymous #3613348 Уровень 90
16 апреля 2026
"ReentrantLock — одна из реализаций интерфейса Lock — класс ReenterantLock. Он позволяет одному и тому же потоку вызывать метод lock, даже если он его вызывал ранее, без освобождения блокировки." А зачем ещё раз вызывать метод lock, если блокировка не освобождалась? Спросила я у ИИ. Это нужно для того, чтобы избежать взаимной блокировки (deadlock) самого себя при использовании рекурсии или вызове нескольких защищенных методов внутри одного класса. ReentrantLock просто увеличивает счетчик (hold count) каждый раз, когда владеющий поток вызывает lock(), и уменьшает его при unlock(). Замок считается полностью свободным только тогда, когда счетчик упадет до нуля. Представь классический пример — рекурсивный обход папок или расчет чего-то важного с защитой данных:

public void recursiveMethod(int count) {
    lock.lock(); // Поток заходит первый раз (счётчик = 1)
    try {
        if (count > 0) {
            System.out.println("Уровень: " + count);
            recursiveMethod(count - 1); // Поток заходит снова (счётчик станет 2, потом 3...)
        }
    } finally {
        lock.unlock(); // Счётчик уменьшается на 1 при каждом выходе
    }
}
Что произошло бы без реентерабельности: 1. Поток вызывает lock.lock() на первом уровне. Успешно. 2. Внутри вызывает сам себя. 3. Снова доходит до lock.lock(). 4. Стоп. Система видит, что замок занят. Поток встает в очередь и засыпает в ожидании освобождения. 5. Но замок освободится только тогда, когда метод завершится. А метод не завершится, пока не пройдет этот lock. Это «тупик» в чистом виде. Благодаря тому, что ReentrantLock узнает «своего», поток просто проходит дальше, инкрементируя внутренний счетчик.
Олег Уровень 106 Expert
13 сентября 2024
Кто-то что-то понял? Или я уже сдавать начал
Oleg Уровень 41
12 ноября 2022
Статья вероятно будет дополняться, как и остальные по многопоточке, тк довольно сумбурно и где например java.util.concurrent.locks.StampedLock
Иван Голубев Уровень 108 Expert
18 сентября 2022
У задачи условие неправильное. На read операции readLock.lock() и readLock.unlock() в try и finally соответственно, а на write операции writeLock.lock() и writeLock.unlock() в try и finally соответственно в задании д.б.