Найти в Дзене

Бинарный семафор против повторно входной блокировки (Reentrant Lock)

В этом руководстве мы рассмотрим бинарные семафоры и повторно входные блокировки (Reentrant Locks). Также мы сравним их между собой, чтобы понять, какая из них лучше подходит для различных ситуаций. Бинарный семафор обеспечивает механизм сигнализации для управления доступом к единственному ресурсу. Иными словами, бинарный семафор реализует взаимное исключение, позволяя только одному потоку одновременно входить в критическую секцию. Для этого он хранит только один доступный "разрешающий" токен. Следовательно, бинарный семафор может находиться только в двух состояниях: разрешение доступно (1) или не доступно (0). Пример простой реализации бинарного семафора с использованием класса Semaphore в Java: Semaphore binarySemaphore = new Semaphore(1);
try {
binarySemaphore.acquire();
assertEquals(0, binarySemaphore.availablePermits());
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
binarySemaphore.release();
assertEquals(1, binarySemaphore.availablePermi
Оглавление

1. Обзор

В этом руководстве мы рассмотрим бинарные семафоры и повторно входные блокировки (Reentrant Locks). Также мы сравним их между собой, чтобы понять, какая из них лучше подходит для различных ситуаций.

2. Что такое бинарный семафор?

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

Для этого он хранит только один доступный "разрешающий" токен. Следовательно, бинарный семафор может находиться только в двух состояниях: разрешение доступно (1) или не доступно (0).

Пример простой реализации бинарного семафора с использованием класса Semaphore в Java:

Semaphore binarySemaphore = new Semaphore(1);
try {
binarySemaphore.acquire();
assertEquals(0, binarySemaphore.availablePermits());
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
binarySemaphore.release();
assertEquals(1, binarySemaphore.availablePermits());
}

Здесь видно, что метод acquire уменьшает количество разрешений на 1, а release — увеличивает.

Также класс Semaphore поддерживает параметр справедливости (fairness). При установке true, справедливость обеспечивает порядок доступа потоков к разрешениям на основе времени ожидания:

Semaphore binarySemaphore = new Semaphore(1, true);

3. Что такое повторно входная блокировка (Reentrant Lock)?

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

Каждый раз, когда поток захватывает блокировку, счётчик удержания увеличивается на 1. Соответственно, при вызове unlock он уменьшается. Ресурс остаётся заблокированным до тех пор, пока счётчик не станет равен нулю.

Пример простой реализации с использованием класса ReentrantLock в Java:

ReentrantLock reentrantLock = new ReentrantLock();
try {
reentrantLock.lock();
assertEquals(1, reentrantLock.getHoldCount());
assertEquals(true, reentrantLock.isLocked());
} finally {
reentrantLock.unlock();
assertEquals(0, reentrantLock.getHoldCount());
assertEquals(false, reentrantLock.isLocked());
}

Если поток повторно входит в блокировку, он должен вызвать unlock столько же раз, чтобы полностью освободить ресурс:

reentrantLock.lock();
reentrantLock.lock();
assertEquals(2, reentrantLock.getHoldCount());
assertEquals(true, reentrantLock.isLocked());

reentrantLock.unlock();
assertEquals(1, reentrantLock.getHoldCount());
assertEquals(true, reentrantLock.isLocked());

reentrantLock.unlock();
assertEquals(0, reentrantLock.getHoldCount());
assertEquals(false, reentrantLock.isLocked());

Как и Semaphore, ReentrantLock поддерживает параметр справедливости:

javaКопироватьРедактироватьReentrantLock reentrantLock = new ReentrantLock(true);

4. Бинарный семафор против Reentrant Lock

4.1. Механизм

Бинарный семафор — это механизм сигнализации, а Reentrant Lock — механизм блокировки.

4.2. Владение

Бинарный семафор не имеет владельца — любой поток может захватить или освободить ресурс.
В Reentrant Lock владелец — это поток, который последним успешно захватил блокировку.

4.3. Повторный вход

Бинарный семафор не поддерживает повторный вход: если поток попытается повторно захватить ресурс, возникнет взаимоблокировка.
Reentrant Lock
поддерживает повторный вход: поток может многократно входить в блокировку.

4.4. Гибкость

Бинарный семафор — более высокоуровневый механизм синхронизации, который позволяет реализовывать собственную логику блокировки и восстановления после deadlock.
Reentrant Lock — низкоуровневый механизм с фиксированной логикой блокировки.

4.5. Модификация

В бинарном семафоре любой поток может вызвать acquire или release, изменяя количество разрешений.
В Reentrant Lock
только владелец может вызывать unlock.

4.6. Восстановление после взаимоблокировки

Бинарный семафор допускает освобождение ресурса любым потоком, что позволяет реализовать восстановление после взаимоблокировки.
В Reentrant Lock восстановление после deadlock затруднено — если поток-владелец "завис", то ресурс остаётся заблокированным.

5. Заключение

В этой статье мы рассмотрели бинарный семафор и повторно входную блокировку.

Сначала мы разобрали их определения и пример реализации в Java. Затем сравнили по ряду параметров: механизм, владение, гибкость и т.д.

Можно сделать вывод, что бинарный семафор обеспечивает механизм взаимного исключения без владения, может быть расширен до полноценной блокировки и проще в восстановлении после deadlock.

Reentrant Lock, в свою очередь, предлагает механизм повторного входа с владением, и хорошо подходит как простой mutex.

Оригинал статьи: https://www.baeldung.com/java-binary-semaphore-vs-reentrant-lock