Класс Semaphore
- Все реализованные интерфейсы:
Serializable
public class Semaphore extends Object implements Serializable
acquire() блокируется, если необходимо, до тех пор, пока разрешение не станет доступным, а затем берет его. Каждый release() добавляет разрешение, потенциально разблокируя заблокированного ожидающего потока. Однако, фактические объекты разрешений не используются; семафор просто хранит количество доступных разрешений и действует соответствующим образом. Семафоры часто используются для ограничения числа потоков, которые могут получить доступ к некоторому (физическому или логическому) ресурсу. Например, вот класс, который использует семафор для управления доступом к пулу элементов:
class Pool {
private static final int MAX_AVAILABLE = 100;
private final Semaphore available = new Semaphore(MAX_AVAILABLE, true);
public Object getItem() throws InterruptedException {
available.acquire();
return getNextAvailableItem();
}
public void putItem(Object x) {
if (markAsUnused(x))
available.release();
}
// Not a particularly efficient data structure; just for demo
protected Object[] items = ...; // whatever kinds of items being managed
protected boolean[] used = new boolean[MAX_AVAILABLE];
protected synchronized Object getNextAvailableItem() {
for (int i = 0; i < MAX_AVAILABLE; ++i) {
if (!used[i]) {
used[i] = true;
return items[i];
}
}
return null; // not reached
}
protected synchronized boolean markAsUnused(Object item) {
for (int i = 0; i < MAX_AVAILABLE; ++i) {
if (item == items[i]) {
if (used[i]) {
used[i] = false;
return true;
} else
return false;
}
}
return false;
}
} Перед получением элемента каждый поток должен получить разрешение от семафора, гарантируя, что элемент доступен для использования. Когда поток завершит работу с элементом, он возвращается в пул, и разрешение возвращается семафору, позволяя другому потоку получить этот элемент. Обратите внимание, что никакая блокировка синхронизации не удерживается при вызове acquire(), поскольку это предотвратит возвращение элемента в пул. Семафор инкапсулирует необходимую синхронизацию для ограничения доступа к пулу, независимо от любой синхронизации, необходимой для поддержания согласованности самого пула.
Семафор, инициализированный единицей и используемый таким образом, что у него всегда доступно не более одного разрешения, может служить блокировкой взаимного исключения. Это более известно как двоичный семафор, потому что он имеет только два состояния: одно разрешение доступно или ноль разрешений доступно. Когда он используется таким образом, двоичный семафор обладает свойством (в отличие от многих Lock реализаций), что «блокировка» может быть освобождена потоком, отличным от владельца (так как семафоры не имеют понятия о владении). Это может быть полезно в некоторых специализированных контекстах, таких как восстановление от тупиков.
Конструктор этого класса необязательно принимает параметр справедливости. Если он установлен в false, этот класс не гарантирует порядок, в котором потоки получают разрешения. В частности, разрешается вторжение, то есть поток, вызывающий acquire(), может получить разрешение раньше потока, который ожидал — логически новый поток помещает себя в начало очереди ожидающих потоков. Когда справедливость установлена в true, семафор гарантирует, что потоки, вызывающие любой из acquire методов, выбираются для получения разрешений в порядке обработки их вызова этих методов (первым пришел — первым обслужен; FIFO). Обратите внимание, что порядок FIFO обязательно применяется к определенным внутренним точкам выполнения в этих методах. Поэтому возможно, что один поток вызовет acquire перед другим, но достигнет точки упорядочивания позже другого, и аналогично при возврате из метода. Также обратите внимание, что безнастроеные tryAcquire методы не учитывают установку справедливости, а возьмут любые доступные разрешения.
Как правило, семафоры, используемые для управления доступом к ресурсам, должны быть инициализированы как справедливые, чтобы гарантировать, что ни один поток не будет лишен доступа к ресурсу. При использовании семафоров для других типов управления синхронизацией преимущества производительности несправедливого упорядочения часто перевешивают соображения справедливости.
Этот класс также предоставляет удобные методы для acquire и release нескольких разрешений за раз. Эти методы, как правило, более эффективны и действенны, чем циклы. Однако они не устанавливают никакого порядка предпочтения. Например, если поток A вызывает s.acquire(3) и поток B вызывает s.acquire(2), и два разрешения становятся доступными, то нет гарантии, что поток B их получит, если его получение не произошло раньше, и семафор s находится в режиме справедливости.
Эффекты согласованности памяти: Действия в потоке до вызова метода «release», такого как release() происходит-до действий, следующих за успешным методом «acquire», таким как acquire() в другом потоке.
- С момента:
- 1.5
- См. также:
Краткое описание конструкторов
| Конструктор | Описание |
|---|---|
Semaphore |
Создает Semaphore с заданным числом разрешений и параметром справедливости nonfair. |
Semaphore |
Создает Semaphore с заданным числом разрешений и заданной настройкой справедливости. |
Краткое описание методов
| Модификатор и тип | Метод | Описание |
|---|---|---|
void |
acquire() |
Получает разрешение от этого семафора, блокируя до тех пор, пока оно не станет доступным или поток не будет прерван. |
void |
acquire |
Получает заданное количество разрешений от этого семафора, блокируя до тех пор, пока все не станут доступными или поток не будет прерван. |
void |
acquireUninterruptibly() |
Получает разрешение от этого семафора, блокируя до тех пор, пока оно не станет доступным. |
void |
acquireUninterruptibly |
Получает заданное количество разрешений от этого семафора, блокируя до тех пор, пока все не станут доступными. |
int |
availablePermits() |
Возвращает текущее количество доступных разрешений в этом семафоре. |
int |
drainPermits() |
Получает и возвращает все разрешения, которые в данный момент доступны, или, если доступно отрицательное количество разрешений, освобождает их. |
protected Collection<Thread> |
getQueuedThreads() |
Возвращает коллекцию, содержащую потоки, которые могут ожидать получения разрешения. |
final int |
getQueueLength() |
Возвращает оценку количества потоков, ожидающих получения разрешения. |
final boolean |
hasQueuedThreads() |
Опрашивает, ожидают ли какие-либо потоки получения разрешения. |
boolean |
isFair() |
Возвращает true, если для этого семафора установлена справедливость. |
protected void |
reducePermits |
Уменьшает количество доступных разрешений на указанное значение. |
void |
release() |
Освобождает разрешение, возвращая его в семафор. |
void |
release |
Освобождает заданное количество разрешений, возвращая их в семафор. |
String |
toString() |
Возвращает строку, идентифицирующую этот семафор, а также его состояние. |
boolean |
tryAcquire() |
Получает разрешение от этого семафора, только если оно доступно в момент вызова. |
boolean |
tryAcquire |
Получает заданное количество разрешений от этого семафора, только если все они доступны в момент вызова. |
boolean |
tryAcquire |
Получает заданное количество разрешений от этого семафора, если все они станут доступными в течение заданного времени ожидания и текущий поток не был прерван. |
boolean |
tryAcquire |
Получает разрешение от этого семафора, если оно станет доступным в течение заданного времени ожидания и текущий поток не был прерван. |
Подробное описание конструкторов
Семафор
public Semaphore(int permits)
Semaphore с заданным количеством разрешений и настройкой справедливости nonfair.- Параметры:
-
permits- начальное количество доступных разрешений. Это значение может быть отрицательным, в этом случае освобождения должны произойти до предоставления каких-либо разрешений на получение.
Семафор
public Semaphore(int permits, boolean fair)
Semaphore с заданным количеством разрешений и заданной настройкой справедливости.- Параметры:
-
permits- начальное количество доступных разрешений. Это значение может быть отрицательным, в этом случае освобождения должны произойти до предоставления каких-либо разрешений на получение. -
fair-trueесли этот семафор гарантирует предоставление разрешений по принципу "первый пришёл — первый обслужен" при конфликте, иначеfalse
Подробное описание методов
acquire
public void acquire() throws InterruptedException
Получает разрешение, если оно доступно, и возвращается немедленно, уменьшая количество доступных разрешений на единицу.
Если разрешение недоступно, текущий поток становится неактивным для планирования потоков и находится в состоянии ожидания до тех пор, пока не произойдёт одно из двух событий:
- Другой поток вызывает метод
release()для этого семафора, и текущий поток следующим получит разрешение; - Другой поток прерывает текущий поток.
Если текущий поток:
- имеет статус прерывания, установленный при входе в этот метод; или
- прерывается во время ожидания разрешения,
InterruptedException, и статус прерывания текущего потока сбрасывается.- Исключение:
-
InterruptedException- если текущий поток прерван
acquireUninterruptibly
public void acquireUninterruptibly()
Получает разрешение, если оно доступно, и возвращается немедленно, уменьшая количество доступных разрешений на единицу.
Если разрешение недоступно, текущий поток становится неактивным для планирования потоков и находится в состоянии ожидания до тех пор, пока другой поток не вызовет метод release() для этого семафора, и текущий поток получит разрешение.
Если текущий поток прерывается во время ожидания разрешения, он продолжит ожидание, но время, когда поток получит разрешение, может измениться по сравнению со временем, которое он получил бы, если бы прерывания не было. Когда поток возвращается из этого метода, его статус прерывания устанавливается.
tryAcquire
public boolean tryAcquire()
Получает разрешение, если оно доступно, и возвращается немедленно со значением true, уменьшая количество доступных разрешений на единицу.
Если разрешение недоступно, этот метод вернётся немедленно со значением false.
Даже если этот семафор настроен на использование политики справедливого порядка, вызов tryAcquire() немедленно получит разрешение, если оно доступно, независимо от того, ожидают ли другие потоки в настоящее время. Такое поведение «вторжения» может быть полезным в некоторых ситуациях, хотя оно нарушает справедливость. Если вы хотите соблюдать настройку справедливости, используйте tryAcquire(0, TimeUnit.SECONDS), который почти эквивалентен (он также обнаруживает прерывание).
- Возвращает:
-
trueесли разрешение было получено иfalseв противном случае
tryAcquire
public boolean tryAcquire(long timeout, TimeUnit unit) throws InterruptedException
Получает разрешение, если оно доступно, и возвращается немедленно со значением true, уменьшая количество доступных разрешений на единицу.
Если разрешение недоступно, текущий поток становится неактивным для планирования потоков и находится в состоянии ожидания до тех пор, пока не произойдёт одно из трёх событий:
- Другой поток вызывает метод
release()для этого семафора, и текущий поток следующим получит разрешение; - Другой поток прерывает текущий поток;
- Заданное время ожидания истекает.
Если разрешение получено, возвращается значение true.
Если текущий поток:
- имеет статус прерывания, установленный при входе в этот метод; или
- прерывается во время ожидания получения разрешения,
InterruptedException, и статус прерывания текущего потока сбрасывается. Если заданное время ожидания истекает, возвращается значение false. Если время меньше или равно нулю, метод не будет ожидать.
- Параметры:
-
timeout- максимальное время ожидания разрешения -
unit- единица измерения времени аргументаtimeout - Возвращает:
-
trueесли разрешение было получено иfalseесли время ожидания истекло до получения разрешения - Исключение:
-
InterruptedException- если текущий поток прерван
release
public void release()
Освобождает разрешение, увеличивая количество доступных разрешений на единицу. Если какие-либо потоки пытаются получить разрешение, выбирается один и получает только что освобождённое разрешение. Этот поток (снова) активируется для планирования потоков.
Нет требования, чтобы поток, освобождающий разрешение, получил это разрешение вызовом acquire(). Правильное использование семафора определяется соглашением программирования в приложении.
acquire
public void acquire(int permits) throws InterruptedException
Получает заданное количество разрешений, если они доступны, и возвращается немедленно, уменьшая количество доступных разрешений на заданную величину. Этот метод имеет тот же эффект, что и цикл for (int i = 0; i < permits; ++i) acquire(); за исключением того, что он атомарно получает все разрешения:
Если недостаточно разрешений, текущий поток становится неактивным для планирования потоков и находится в состоянии ожидания, пока не произойдёт одно из двух событий:
- Другой поток вызывает один из методов
releaseдля этого семафора, и текущий поток должен получить разрешения, а количество доступных разрешений удовлетворяет этому запросу; или - Другой поток прерывает текущий поток.
Если текущий поток:
- имеет статус прерывания, установленный при входе в этот метод; или
- прерывается во время ожидания разрешения,
InterruptedException, и статус прерывания текущего потока сбрасывается. Любые разрешения, которые должны были быть назначены этому потоку, вместо этого назначаются другим потокам, пытающимся получить разрешения, как если бы разрешения были предоставлены вызовом release().- Параметры:
-
permits- количество разрешений для получения - Исключение:
-
InterruptedException- если текущий поток прерван -
IllegalArgumentException- еслиpermitsотрицательно
acquireUninterruptibly
public void acquireUninterruptibly(int permits)
Получает заданное количество разрешений, если они доступны, и возвращается немедленно, уменьшая количество доступных разрешений на заданную величину. Этот метод имеет тот же эффект, что и цикл for (int i = 0; i < permits; ++i) acquireUninterruptibly(); за исключением того, что он атомарно получает все разрешения:
Если недостаточно разрешений, текущий поток становится неактивным для планирования потоков и находится в состоянии ожидания, пока другой поток не вызовет один из методов release для этого семафора, и текущий поток должен получить разрешения, а количество доступных разрешений удовлетворяет этому запросу.
Если текущий поток прерывается во время ожидания разрешений, он продолжит ожидание, и его позиция в очереди не изменяется. Когда поток возвращается из этого метода, его статус прерывания устанавливается.
- Параметры:
-
permits- количество разрешений для получения - Исключение:
-
IllegalArgumentException- еслиpermitsотрицательно
tryAcquire
public boolean tryAcquire(int permits)
Получает указанное количество разрешений, если они доступны, и возвращает немедленно значение true, уменьшая количество доступных разрешений на указанную величину.
Если недостаточно разрешений, то этот метод вернёт немедленно значение false и количество доступных разрешений останется неизменным.
Даже когда этот семафор настроен на использование политики справедливого порядка, вызов tryAcquire будет немедленно получить разрешение, если оно доступно, независимо от того, ожидают ли другие потоки. Это поведение «вторжения» может быть полезным в определенных обстоятельствах, хотя оно нарушает справедливость. Если вы хотите соблюдать настройку справедливости, используйте tryAcquire(permits, 0, TimeUnit.SECONDS), который почти эквивалентен (он также обнаруживает прерывание).
- Parameters:
-
permits- количество разрешений для получения - Returns:
-
trueесли разрешения были получены иfalseв противном случае - Throws:
-
IllegalArgumentException- еслиpermitsотрицательно
tryAcquire
public boolean tryAcquire(int permits, long timeout, TimeUnit unit) throws InterruptedException
Получает указанное количество разрешений, если они доступны, и возвращает немедленно значение true, уменьшая количество доступных разрешений на указанную величину.
Если недостаточно разрешений, то текущий поток отключается для планирования потоков и находится в спящем режиме до тех пор, пока не произойдёт одно из трёх событий:
- Другой поток вызывает один из методов
releaseдля этого семафора, и текущий поток получает разрешения, а количество доступных разрешений удовлетворяет этому запросу; или - Другой поток прерывает текущий поток; или
- Заданное время ожидания истекло.
Если разрешения получены, возвращается значение true.
Если у текущего потока:
- Флаг прерывания установлен при входе в этот метод; или
- Поток прерывается во время ожидания получения разрешений,
InterruptedException, и флаг прерывания текущего потока сбрасывается. Любые разрешения, которые должны были быть назначены этому потоку, вместо этого назначаются другим потокам, пытающимся получить разрешения, как если бы разрешения были доступны вызовом release(). Если заданное время ожидания истекло, возвращается значение false. Если время равно или меньше нуля, метод вообще не будет ждать. Любые разрешения, которые должны были быть назначены этому потоку, вместо этого назначаются другим потокам, пытающимся получить разрешения, как если бы разрешения были доступны вызовом release().
- Parameters:
-
permits- количество разрешений для получения -
timeout- максимальное время ожидания разрешений -
unit- единица измерения времени для аргументаtimeout - Returns:
-
trueесли все разрешения были получены иfalseесли время ожидания истекло до получения всех разрешений - Throws:
-
InterruptedException- если текущий поток прерывается -
IllegalArgumentException- еслиpermitsотрицательно
release
public void release(int permits)
Освобождает указанное количество разрешений, увеличивая количество доступных разрешений на эту величину. Если какие-либо потоки пытаются получить разрешения, то выбирается один поток и получает разрешения, которые только что были освобождены. Если количество доступных разрешений удовлетворяет запросу этого потока, то этот поток снова активируется для планирования потоков; в противном случае поток будет ждать, пока не станет доступно достаточное количество разрешений. Если после удовлетворения запроса этого потока всё ещё есть доступные разрешения, то они поочерёдно назначаются другим потокам, пытающимся получить разрешения.
Нет требования, чтобы поток, который освобождает разрешение, должен был получить это разрешение, вызвав acquire. Правильное использование семафора определяется соглашениями программирования в приложении.
- Parameters:
-
permits- количество разрешений для освобождения - Throws:
-
IllegalArgumentException- еслиpermitsотрицательно
availablePermits
public int availablePermits()
Этот метод обычно используется для отладки и тестирования.
- Returns:
- количество разрешений, доступных в этом семафоре
drainPermits
public int drainPermits()
- Returns:
- количество полученных разрешений или, если отрицательно, количество освобожденных разрешений
reducePermits
protected void reducePermits(int reduction)
acquire тем, что он не блокирует ожидание разрешений.- Parameters:
-
reduction- количество разрешений для удаления - Throws:
-
IllegalArgumentException- еслиreductionотрицательно
isFair
public boolean isFair()
true если для этого семафора установлена справедливость.- Returns:
-
trueесли для этого семафора установлена справедливость
hasQueuedThreads
public final boolean hasQueuedThreads()
true не гарантирует, что какой-либо другой поток когда-либо получит. Этот метод предназначен в основном для мониторинга состояния системы.- Returns:
-
trueесли могут ожидать другие потоки
getQueueLength
public final int getQueueLength()
- Returns:
- приблизительное количество ожидающих потоков
getQueuedThreads
protected Collection<Thread> getQueuedThreads()
- Returns:
- коллекция потоков
toString
public String toString()
"Permits =" и количество разрешений.- Overrides:
-
toStringв классеObject - Returns:
- строка, идентифицирующая этот семафор и его состояние
© 1993, 2021, Oracle and/or its affiliates. All rights reserved.
Documentation extracted from Debian's OpenJDK Development Kit package.
Licensed under the GNU General Public License, version 2, with the Classpath Exception.
Various third party code in OpenJDK is licensed under different licenses (see Debian package).
Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates.
https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/concurrent/Semaphore.html