Класс 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 |
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)
- Параметры:
-
permits- начальное количество доступных разрешений. Это значение может быть отрицательным, в этом случае освобождения должны произойти до того, как будут предоставлены какие-либо приобретения.
Семафор
public Semaphore(int permits, boolean fair)
- Параметры:
-
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, если для этого семафора справедливость установлена в значение true.- Returns:
-
true, если для этого семафора справедливость установлена в значение true
hasQueuedThreads
public final boolean hasQueuedThreads()
true не гарантирует, что какой-либо другой поток когда-либо получит разрешения. Этот метод предназначен в первую очередь для мониторинга состояния системы.- Returns:
-
true, если могут быть другие потоки, ожидающие получения
getQueueLength
public final int getQueueLength()
- Returns:
- оцененное количество потоков, ожидающих этого замка
getQueuedThreads
protected Collection<Thread> getQueuedThreads()
- Returns:
- коллекция потоков
toString
© 1993, 2025, 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://download.java.net/java/early_access/jdk24/docs/api/java.base/java/util/concurrent/Semaphore.html