Ответ
ReentrantLock — это реализация интерфейса Lock из пакета java.util.concurrent.locks, предоставляющая механизм взаимного исключения (mutex) с расширенными возможностями по сравнению с ключевым словом synchronized.
Ключевые особенности:
- Повторная входимость (Reentrancy): Поток, уже удерживающий блокировку, может захватить её повторно без взаимной блокировки (deadlock).
- Честность (Fairness): При создании можно указать политику честности (
fair). Честная блокировка (new ReentrantLock(true)) предоставляет доступ потокам в порядке FIFO, но снижает общую пропускную способность. - Прерываемое ожидание: Метод
lockInterruptibly()позволяет прервать поток, ожидающий блокировку. - Попытка захвата с таймаутом: Метод
tryLock(long timeout, TimeUnit unit)пытается получить блокировку в течение заданного времени.
Пример использования:
import java.util.concurrent.locks.ReentrantLock;
ReentrantLock lock = new ReentrantLock();
lock.lock(); // Захват блокировки
try {
// Критическая секция
sharedResource.modify();
} finally {
lock.unlock(); // Освобождение блокировки ВСЕГДА в finally-блоке
}
Сравнение с synchronized: |
Особенность | synchronized |
ReentrantLock |
|---|---|---|---|
| Поддержка tryLock | Нет | Да (с таймаутом) | |
| Честность | Нет (не гарантируется) | Да (опционально) | |
| Прерываемость | Нет (блокировка не прерывается) | Да (lockInterruptibly) |
|
| Условные переменные | Одно (wait/notify) |
Множество (Condition) |
|
| Синтаксис | Встроенное ключевое слово | Явный API, требует unlock в finally |
Когда использовать? ReentrantLock выбирают, когда необходимы продвинутые функции: неблокирующие попытки захвата (tryLock), честное планирование, работа с несколькими условиями ожидания (Condition) или необходимость прерываемого ожидания блокировки.
Ответ 18+ 🔞
Да ты посмотри, что за зверь такой — ReentrantLock! Это ж не просто какая-нибудь синхронизация, это целый арсенал из пакета java.util.concurrent.locks. Если synchronized — это как тупой кухонный нож, то ReentrantLock — это швейцарский армейский нож с фишками, от которых глаза на лоб лезут.
Чем он так охуенен, спросишь?
- Повторная входимость (Reentrancy): Ну, представим, поток уже взял блокировку. А ему надо зайти ещё раз в метод, который тоже её требует. С обычным мьютексом — пиши пропало, deadlock, зависни и сдохни. А этот красавец говорит: «Да хуй с тобой, заходи, ты же свой, блядь». Захватил — и всё, никакой взаимной блокировки.
- Честность (Fairness): Тут вообще цирк. Можно создать блокировку с флагом честности (
new ReentrantLock(true)). Тогда она, эта сволочь, будет пускать потоки строго по очереди, как в советской поликлинике — кто первый встал, того и тапки. Правда, производительность просядет, как у мудака после трёх дней запоя, но зато справедливость, мать её! - Прерываемое ожидание: Метод
lockInterruptibly()— это просто песня. Ждёт поток блокировку, а ты ему — раз! —interrupt(). И он не будет висеть, как идиот, до скончания веков, а вежливо так, с пониманием, вылетит сInterruptedException. Красота! - Попытка захвата с таймаутом:
tryLock(long timeout, TimeUnit unit)— это вообще верх наглости. «Дай-ка, — говорит поток, — попробую взять блокировку, но если за 5 секунд не выйдет — да похуй, пойду другие дела делать». Не получилось — и не надо, без истерик.
Как этим пользоваться, чтобы не обосраться? Смотри, вот пример, его в голове выгравируй:
import java.util.concurrent.locks.ReentrantLock;
ReentrantLock lock = new ReentrantLock();
lock.lock(); // Всё, взял замок, теперь я царь и бог
try {
// Твоя критическая секция. Делай что хочешь с общим ресурсом.
sharedResource.modifyTheFuckOutOfIt();
} finally {
lock.unlock(); // ЭТО ВАЖНО, БЛЯДЬ! Освобождай ВСЕГДА в finally!
}
Запомни, как «Отче наш»: unlock() — только в finally. Иначе если в критической секции вылетит исключение — твоя блокировка навечно повиснет, и все остальные потоки будут ждать её, как дураки, до тепловой смерти вселенной.
Ну и что лучше: synchronized или этот ваш ReentrantLock?
Сравнительная таблица, ёпта, чтобы всё стало ясно:
| Особенность | synchronized (старый дедок) |
ReentrantLock (продвинутый чувак) |
|---|---|---|
| Поддержка tryLock | Нет, жди пока не синешь | Да, и с таймаутом, чтоб не засиживался |
| Честность | Хуй там, а не честность. Кто как схватит. | Да, можно включить, если хочешь справедливости (но медленнее) |
| Прерываемость | Нет. Заблокировался — терпи, мудак. | Да, можно вежливо попросить прекратить (lockInterruptibly) |
| Условные переменные | Одна, через wait()/notify(). Тесно, душно. |
Множество, через Condition. Раздельные очереди ожидания — просто космос! |
| Синтаксис | Встроено в язык, просто и коротко. | Явный API. Больше власти, но и больше ответственности. Не забудь unlock()! |
Так когда же его, блядь, использовать?
Да когда тебе мало возможностей этого убогого synchronized! Когда нужно:
- Сказать «попробуй взять блокировку, а не получится — и хуй с ним» (
tryLock). - Устроить честную очередь из потоков (честный
fairрежим). - Работать с несколькими условиями ожидания (например, «очередь полна» и «очередь пуста» — это два разных
Condition). - Иметь возможность вежливо прервать поток, который ждёт блокировку.
В общем, ReentrantLock — это для тех, кто перерос примитивные игрушки и хочет контролировать многопоточность, как бог. Главное — не накосячить с unlock(), а то будет овердохуища проблем.