Класс 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​(int permits)

Создаёт Semaphore с заданным числом разрешений и настройкой справедливости nonfair.

Semaphore​(int permits, boolean fair)

Создаёт Semaphore с заданным числом разрешений и заданной настройкой справедливости.

Методы

Модификатор и тип Метод Описание
void acquire()

Получает разрешение от этого семафора, блокируясь до тех пор, пока оно не станет доступным, или поток не будет прерван.

void acquire​(int permits)

Получает заданное количество разрешений от этого семафора, блокируясь до тех пор, пока все не станут доступными, или поток не будет прерван.

void acquireUninterruptibly()

Получает разрешение от этого семафора, блокируясь до тех пор, пока оно не станет доступным.

void acquireUninterruptibly​(int permits)

Получает заданное количество разрешений от этого семафора, блокируясь до тех пор, пока все не станут доступными.

int availablePermits()

Возвращает текущее количество доступных разрешений в этом семафоре.

int drainPermits()

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

protected Collection<Thread> getQueuedThreads()

Возвращает коллекцию, содержащую потоки, которые могут ожидать получения.

int getQueueLength()

Возвращает приблизительное количество потоков, ожидающих получения.

boolean hasQueuedThreads()

Определяет, ожидают ли какие-либо потоки получения.

boolean isFair()

Возвращает true, если в этом семафоре установлена справедливость.

protected void reducePermits​(int reduction)

Уменьшает количество доступных разрешений на указанную величину.

void release()

Освобождает разрешение, возвращая его семафору.

void release​(int permits)

Освобождает заданное количество разрешений, возвращая их семафору.

String toString()

Возвращает строку, идентифицирующую этот семафор, а также его состояние.

boolean tryAcquire()

Получает разрешение от этого семафора, только если оно доступно в момент вызова.

boolean tryAcquire​(int permits)

Получает заданное количество разрешений от этого семафора, только если все они доступны в момент вызова.

boolean tryAcquire​(int permits, long timeout, TimeUnit unit)

Получает заданное количество разрешений от этого семафора, если все они становятся доступными в течение заданного времени ожидания, и текущий поток не был прерван.

boolean tryAcquire​(long timeout, TimeUnit unit)

Получает разрешение от этого семафора, если оно становится доступным в течение заданного времени ожидания, и текущий поток не был прерван.

Методы, объявленные в классе java.lang.Object

clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait

Конструкторы

Семафор

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), который почти эквивалентен (он также обнаруживает прерывание).

Параметры:
permits - количество разрешений для получения
Возвращает:
true если разрешения были получены и false в противном случае
Исключения:
IllegalArgumentException - если permits отрицательно

tryAcquire

public boolean tryAcquire(int permits,
                          long timeout,
                          TimeUnit unit)
                   throws InterruptedException

Получает заданное количество разрешений из этого семафора, если все станут доступными в течение заданного времени ожидания, а текущий поток не был прерван.

Получает заданное количество разрешений, если они доступны и возвращается немедленно, со значением true, уменьшая количество доступных разрешений на заданную величину.

Если недостаточно разрешений доступны, то текущий поток становится неактивным для целей планирования потоков и находится в спящем состоянии, пока не произойдёт одно из трёх:

  • Другой поток вызывает один из методов release для этого семафора, и текущий поток следующим должен получить разрешения, и количество доступных разрешений удовлетворяет этому запросу; или
  • Другой поток прерывает текущий поток; или
  • Указанное время ожидания истекает.

Если разрешения получены, то возвращается значение true.

Если текущий поток:

  • имеет свой статус прерывания, установленный при входе в этот метод; или
  • бывает прерван во время ожидания получения разрешений,
то выбрасывается исключение InterruptedException, и статус прерывания текущего потока сбрасывается. Любые разрешения, которые должны были быть назначены этому потоку, вместо этого назначаются другим потокам, пытающимся получить разрешения, как если бы разрешения были сделаны доступными вызовом release().

Если указанное время ожидания истекает, то возвращается значение false. Если время меньше или равно нулю, метод вообще не будет ждать. Любые разрешения, которые должны были быть назначены этому потоку, вместо этого назначаются другим потокам, пытающимся получить разрешения, как если бы разрешения были сделаны доступными вызовом release().

Параметры:
permits - количество разрешений для получения
timeout - максимальное время ожидания разрешений
unit - единица измерения времени для аргумента timeout
Возвращает:
true если все разрешения были получены и false если время ожидания истекло, прежде чем все разрешения были получены
Выбрасывает:
InterruptedException - если текущий поток прерван
IllegalArgumentException - если permits отрицательно

release

public void release(int permits)

Освобождает заданное количество разрешений, возвращая их семафору.

Освобождает заданное количество разрешений, увеличивая количество доступных разрешений на эту величину. Если какие-либо потоки пытаются получить разрешения, то выбирается один поток и получает разрешения, которые только что были освобождены. Если количество доступных разрешений удовлетворяет запросу этого потока, то этот поток (снова) разрешается для планирования потоков; в противном случае поток будет ждать, пока не будет достаточно разрешений. Если после удовлетворения запроса этого потока всё ещё доступны разрешения, то эти разрешения по очереди назначаются другим потокам, пытающимся получить разрешения.

Нет требования, чтобы поток, освобождающий разрешение, должен был получить это разрешение, вызвав acquire. Правильное использование семафора устанавливается соглашением по программированию в приложении.

Параметры:
permits - количество разрешений для освобождения
Выбрасывает:
IllegalArgumentException - если permits отрицательно

availablePermits

public int availablePermits()

Возвращает текущее количество разрешений, доступных в этом семафоре.

Этот метод обычно используется для отладки и тестирования.

Возвращает:
количество разрешений, доступных в этом семафоре

drainPermits

public int drainPermits()

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

Возвращает:
количество полученных разрешений или, если отрицательное, количество освобождённых

reducePermits

protected void reducePermits(int reduction)

Уменьшает количество доступных разрешений на указанное уменьшение. Этот метод может быть полезен в подклассах, которые используют семафоры для отслеживания ресурсов, которые становятся недоступными. Этот метод отличается от acquire тем, что он не блокируется, ожидая, пока разрешения станут доступными.

Параметры:
reduction - количество разрешений для удаления
Выбрасывает:
IllegalArgumentException - если reduction отрицательно

isFair

public boolean isFair()

Возвращает true , если для этого семафора справедливость установлена в значение true.

Возвращает:
true если для этого семафора справедливость установлена в значение true

hasQueuedThreads

public final boolean hasQueuedThreads()

Опрашивает, ожидают ли какие-либо потоки получения разрешений. Обратите внимание, что из-за отмены, которая может произойти в любое время, возврат true не гарантирует, что какой-либо другой поток когда-либо получит разрешение. Этот метод предназначен в основном для мониторинга состояния системы.

Возвращает:
true если могут быть другие потоки, ожидающие получения блокировки

getQueueLength

public final int getQueueLength()

Возвращает оценку количества потоков, ожидающих получения. Значение является только оценкой, поскольку количество потоков может динамически изменяться во время прохода по внутренним структурам данных этим методом. Этот метод предназначен для мониторинга состояния системы, а не для управления синхронизацией.

Возвращает:
оцененное количество потоков, ожидающих этой блокировки

getQueuedThreads

protected Collection<Thread> getQueuedThreads()

Возвращает коллекцию, содержащую потоки, которые могут ожидать получения. Поскольку фактический набор потоков может динамически изменяться во время построения этого результата, возвращаемая коллекция является только приблизительной оценкой. Элементы возвращаемой коллекции не упорядочены.

Возвращает:
коллекцию потоков

toString

public String toString()

Возвращает строку, идентифицирующую этот семафор, а также его состояние. Состояние, в скобках, включает строку "Permits =" за которой следует количество разрешений.

Переопределяет:
toString в классе Object
Возвращает:
строку, идентифицирующую этот семафор, а также его состояние

© 1993, 2020, 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/11/docs/api/java.base/java/util/concurrent/Semaphore.html

Spec-Zone .ru
спецификации, руководства, описания, API