Автор оригинала: Anshul Bansal.
1. Обзор
В этом уроке мы рассмотрим двоичные семафоры и реентерабельные блокировки. Кроме того, мы сравним их друг с другом, чтобы понять, какой из них лучше всего подходит в обычных ситуациях.
2. Что такое Двоичный Семафор?
Двоичный семафор обеспечивает механизм сигнализации при доступе к одному ресурсу. Другими словами, двоичный семафор обеспечивает взаимное исключение, которое позволяет только одному потоку одновременно обращаться к критическому разделу .
Для этого он сохраняет только одно разрешение на доступ. Следовательно, двоичный семафор имеет только два состояния: одно доступное разрешение или ноль доступных разрешений .
Давайте обсудим простую реализацию двоичного семафора с использованием класса 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 уменьшает количество доступных разрешений на единицу. Аналогичным образом, метод release увеличивает количество доступных разрешений на единицу.
Кроме того, класс Семафор предоставляет параметр справедливость . Если установлено значение true , параметр справедливость обеспечивает порядок, в котором запрашивающие потоки получают разрешения (в зависимости от времени ожидания):
Semaphore binarySemaphore = new Semaphore(1, true);
3. Что такое Реентерабельный Замок?
повторная блокировка-это механизм взаимного исключения , который позволяет потокам повторно входить в блокировку ресурса (несколько раз) без ситуации взаимоблокировки .
Поток, входящий в блокировку, каждый раз увеличивает количество удержаний на единицу. Аналогично, количество удержаний уменьшается при запросе разблокировки. Поэтому ресурс блокируется до тех пор, пока счетчик не вернется к нулю .
Например, давайте рассмотрим простую реализацию с использованием класса 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()); }
Здесь метод lock увеличивает количество удержаний на единицу и блокирует ресурс. Аналогично, метод 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());
Подобно классу Семафор , класс ReentrantLock также поддерживает параметр справедливость :
ReentrantLock reentrantLock = new ReentrantLock(true);
4. Двоичный семафор против Реентерабельный замок
4.1. Механизм
Двоичный семафор-это тип сигнального механизма , в то время как реентерабельная блокировка-это механизм блокировки.
4.2. Право собственности
Ни один поток не является владельцем двоичного семафора. Однако последний поток, который успешно заблокировал ресурс, является владельцем повторной блокировки .
4.3. Природа
Двоичные семафоры по своей природе не являются реентерабельными, что означает, что один и тот же поток не может повторно получить критический раздел, иначе это приведет к тупиковой ситуации.
С другой стороны, reentrantlock по своей природе позволяет повторно вводить блокировку одним и тем же потоком несколько раз.
4.4. Гибкость
Двоичный семафор обеспечивает механизм синхронизации более высокого уровня , позволяя пользовательскую реализацию механизма блокировки и восстановления взаимоблокировки. Таким образом, это дает больше контроля разработчикам.
Однако реентерабельная блокировка представляет собой синхронизацию низкого уровня с фиксированным механизмом блокировки .
4.5. Изменение
Двоичные семафоры поддерживают такие операции, как ожидание и сигнал (получение и освобождение в случае класса Java Semaphore ), чтобы разрешить изменение доступных разрешений любым процессом.
С другой стороны, только тот же поток, который заблокировал/разблокировал ресурс, может изменить повторную блокировку.
4.6. Восстановление тупиковой ситуации
Двоичные семафоры обеспечивают механизм освобождения от владения . Таким образом, любой поток может освободить разрешение на восстановление взаимоблокировки двоичного семафора.
Напротив, восстановление тупика трудно достичь в случае повторной блокировки. Например, если поток-владелец реентерабельной блокировки переходит в спящий режим или бесконечное ожидание, освободить ресурс будет невозможно, и в результате возникнет ситуация взаимоблокировки.
5. Заключение
В этой короткой статье мы исследовали двоичные семафорные и реентерабельные блокировки.
Во-первых, мы обсудили базовое определение двоичного семафора и реентерабельной блокировки, а также базовую реализацию в Java. Затем мы сравнили их друг с другом на основе нескольких параметров, таких как механизм, владение и гибкость.
Мы, безусловно, можем заключить, что двоичный семафор обеспечивает механизм сигнализации, не основанный на праве собственности, для взаимного исключения . В то же время он может быть дополнительно расширен, чтобы обеспечить возможности блокировки с легким восстановлением тупиковой ситуации.
С другой стороны, повторная блокировка обеспечивает повторное взаимное исключение с возможностями блокировки на основе владельца и полезна в качестве простого мьютекса.
Как обычно, исходный код доступен на GitHub .