Spec-Zone.ru › OpenJDK 25

Интерфейс Condition

Все известные реализующие классы:
AbstractQueuedLongSynchronizer.ConditionObject, AbstractQueuedSynchronizer.ConditionObject
public interface Condition
Condition выделяет методы монитора Object (wait, notify и notifyAll) в отдельные объекты, чтобы обеспечить возможность иметь несколько множеств ожидания для одного объекта, сочетая их с произвольными реализациями Lock. В случаях, когда Lock заменяет использование методов и операторов synchronized, Condition заменяет использование методов монитора Object.

Условия (также известные как очереди условий или переменные условий) позволяют одному потоку приостановить выполнение (то есть «ожидать»), пока другой поток не уведомит его о том, что некоторое условие состояния, возможно, теперь истинно. Поскольку доступ к этой общей информации о состоянии осуществляется в разных потоках, он должен быть защищён, поэтому с условием связывается блокировка определённого вида. Ключевое свойство ожидания условия заключается в том, что оно атомарно освобождает связанную блокировку и приостанавливает текущий поток, как и Object.wait.

Экземпляр Condition неразрывно связан с блокировкой. Чтобы получить экземпляр Condition для определённого экземпляра Lock, используйте его метод newCondition().

Предположим, например, что у нас есть буфер ограниченного размера, поддерживающий методы put и take. Если предпринимается попытка take для пустого буфера, поток будет заблокирован, пока не появится элемент; если предпринимается попытка put для полного буфера, поток будет заблокирован, пока не освободится место. Мы хотим, чтобы потоки put и take ожидали в отдельных множествах ожидания, чтобы можно было оптимизировать уведомления, оповещая только один поток за раз, когда в буфере появляются элементы или освобождается место. Этого можно добиться с помощью двух экземпляров Condition.

class BoundedBuffer<E> {
  final Lock lock = new ReentrantLock();
  final Condition notFull  = lock.newCondition(); 
  final Condition notEmpty = lock.newCondition(); 

  final Object[] items = new Object[100];
  int putptr, takeptr, count;

  public void put(E x) throws InterruptedException {
    lock.lock();
    try {
      while (count == items.length)
        notFull.await();
      items[putptr] = x;
      if (++putptr == items.length) putptr = 0;
      ++count;
      notEmpty.signal();
    } finally {
      lock.unlock();
    }
  }

  public E take() throws InterruptedException {
    lock.lock();
    try {
      while (count == 0)
        notEmpty.await();
      E x = (E) items[takeptr];
      if (++takeptr == items.length) takeptr = 0;
      --count;
      notFull.signal();
      return x;
    } finally {
      lock.unlock();
    }
  }
}
(Класс ArrayBlockingQueue предоставляет эту функциональность, поэтому нет необходимости реализовывать этот пример класса для использования.)

Реализация Condition может обеспечивать поведение и семантику, отличающиеся от поведения и семантики методов монитора Object, например гарантированный порядок уведомлений или отсутствие требования удерживать блокировку при отправке уведомлений. Если реализация обеспечивает такую специализированную семантику, она должна документировать её.

Обратите внимание, что экземпляры Condition являются обычными объектами и сами могут использоваться в качестве цели оператора synchronized, а также для них могут вызываться собственные методы монитора wait и notify. Захват блокировки монитора экземпляра Condition или использование его методов монитора никак не связано с захватом Lock, связанной с этим Condition, либо с использованием его методов ожидания и сигнализации. Во избежание путаницы рекомендуется никогда не использовать экземпляры Condition таким образом, за исключением, возможно, их собственной реализации.

Если не указано иное, передача значения null для любого параметра приводит к выбрасыванию исключения NullPointerException.

Особенности реализации

При ожидании Condition в общем случае допускается «ложное пробуждение» в качестве уступки семантике базовой платформы. Для большинства прикладных программ это имеет небольшое практическое значение, поскольку ожидание Condition всегда должно выполняться в цикле с проверкой предиката состояния, которого ожидают. Реализация может исключить возможность ложных пробуждений, но прикладным программистам рекомендуется всегда исходить из того, что они могут происходить, и поэтому всегда ожидать в цикле.

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

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

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

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

Начиная с:
1.5

Краткое описание методов

Модификатор и тип Метод Описание
void await()
Переводит текущий поток в состояние ожидания до получения сигнала или прерывания.
boolean await(long time, TimeUnit unit)
Переводит текущий поток в состояние ожидания до получения сигнала или прерывания либо до истечения указанного времени ожидания.
long awaitNanos(long nanosTimeout)
Переводит текущий поток в состояние ожидания до получения сигнала или прерывания либо до истечения указанного времени ожидания.
void awaitUninterruptibly()
Переводит текущий поток в состояние ожидания до получения сигнала.
boolean awaitUntil(Date deadline)
Переводит текущий поток в состояние ожидания до получения сигнала или прерывания либо до наступления указанного крайнего срока.
void signal()
Пробуждает один ожидающий поток.
void signalAll()
Пробуждает все ожидающие потоки.

Подробное описание методов

await

void await() throws InterruptedException
Переводит текущий поток в состояние ожидания до получения сигнала или прерывания.

Связанная с этим Condition блокировка атомарно освобождается, а текущий поток исключается из планирования и остаётся в спящем состоянии до наступления одного из четырёх событий:

  • Другой поток вызывает для этого Condition метод signal(), и текущий поток оказывается выбранным для пробуждения; или
  • Другой поток вызывает для этого Condition метод signalAll(); или
  • Другой поток прерывает текущий поток, и поддерживается прерывание приостановки потока; или
  • Происходит «ложное пробуждение».

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

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

  • входит в этот метод с установленным флагом прерывания; или
  • прерывается во время ожидания, и поддерживается прерывание приостановки потока,
выбрасывается InterruptedException, а флаг прерывания текущего потока сбрасывается. В первом случае не определено, выполняется ли проверка на прерывание до освобождения блокировки.

Особенности реализации

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

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

Выбрасывает:
InterruptedException — если текущий поток прерван (и поддерживается прерывание приостановки потока)

awaitUninterruptibly

void awaitUninterruptibly()
Переводит текущий поток в состояние ожидания до получения сигнала.

Связанная с этим условием блокировка атомарно освобождается, а текущий поток исключается из планирования и остаётся в спящем состоянии до наступления одного из трёх событий:

  • Другой поток вызывает для этого Condition метод signal(), и текущий поток оказывается выбранным для пробуждения; или
  • Другой поток вызывает для этого Condition метод signalAll(); или
  • Происходит «ложное пробуждение».

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

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

Особенности реализации

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

awaitNanos

long awaitNanos(long nanosTimeout) throws InterruptedException
Переводит текущий поток в состояние ожидания до получения сигнала или прерывания либо до истечения указанного времени ожидания.

Связанная с этим условием блокировка атомарно освобождается, а текущий поток исключается из планирования и остаётся в спящем состоянии до наступления одного из пяти событий:

  • Другой поток вызывает для этого Condition метод signal(), и текущий поток оказывается выбранным для пробуждения; или
  • Другой поток вызывает для этого Condition метод signalAll(); или
  • Другой поток прерывает текущий поток, и поддерживается прерывание приостановки потока; или
  • Истекает указанное время ожидания; или
  • Происходит «ложное пробуждение».

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

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

  • входит в этот метод с установленным флагом прерывания; или
  • прерывается во время ожидания, и поддерживается прерывание приостановки потока,
выбрасывается InterruptedException, а флаг прерывания текущего потока сбрасывается. В первом случае не определено, выполняется ли проверка на прерывание до освобождения блокировки.

При возврате метод возвращает оценку количества наносекунд, оставшихся до истечения заданного значения nanosTimeout, или значение, меньшее либо равное нулю, если время ожидания истекло. Это значение можно использовать, чтобы определить, следует ли продолжить ожидание и как долго, если метод завершился, но ожидаемое условие всё ещё не выполнено. Обычно этот метод используется следующим образом:

boolean aMethod(long timeout, TimeUnit unit)
    throws InterruptedException {
  long nanosRemaining = unit.toNanos(timeout);
  lock.lock();
  try {
    while (!conditionBeingWaitedFor()) {
      if (nanosRemaining <= 0L)
        return false;
      nanosRemaining = theCondition.awaitNanos(nanosRemaining);
    }
    // ...
    return true;
  } finally {
    lock.unlock();
  }
}

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

Особенности реализации

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

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

Параметры:
nanosTimeout — максимальное время ожидания в наносекундах
Возвращает:
оценку разности между значением nanosTimeout и временем, проведённым в ожидании к моменту возврата из этого метода. Положительное значение можно использовать как аргумент последующего вызова этого метода, чтобы дождаться истечения заданного времени. Значение, меньшее либо равное нулю, означает, что времени не осталось.
Выбрасывает:
InterruptedException — если текущий поток прерван (и поддерживается прерывание приостановки потока)

await

boolean await(long time, TimeUnit unit) throws InterruptedException
Переводит текущий поток в состояние ожидания до получения сигнала или прерывания либо до истечения указанного времени ожидания. По поведению этот метод эквивалентен:
 awaitNanos(unit.toNanos(time)) > 0
Параметры:
time — максимальное время ожидания
unit — единица измерения аргумента time
Возвращает:
false, если истечение времени ожидания было обнаружено до возврата из метода; в противном случае — true
Выбрасывает:
InterruptedException — если текущий поток прерван (и поддерживается прерывание приостановки потока)

awaitUntil

boolean awaitUntil(Date deadline) throws InterruptedException
Переводит текущий поток в состояние ожидания до получения сигнала или прерывания либо до наступления указанного крайнего срока.

Связанная с этим условием блокировка атомарно освобождается, а текущий поток исключается из планирования и остаётся в спящем состоянии до наступления одного из пяти событий:

  • Другой поток вызывает для этого Condition метод signal(), и текущий поток оказывается выбранным для пробуждения; или
  • Другой поток вызывает для этого Condition метод signalAll(); или
  • Другой поток прерывает текущий поток, и поддерживается прерывание приостановки потока; или
  • Наступает указанный крайний срок; или
  • Происходит «ложное пробуждение».

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

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

  • входит в этот метод с установленным флагом прерывания; или
  • прерывается во время ожидания, и поддерживается прерывание приостановки потока,
выбрасывается InterruptedException, а флаг прерывания текущего потока сбрасывается. В первом случае не определено, выполняется ли проверка на прерывание до освобождения блокировки.

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

boolean aMethod(Date deadline)
    throws InterruptedException {
  boolean stillWaiting = true;
  lock.lock();
  try {
    while (!conditionBeingWaitedFor()) {
      if (!stillWaiting)
        return false;
      stillWaiting = theCondition.awaitUntil(deadline);
    }
    // ...
    return true;
  } finally {
    lock.unlock();
  }
}

Особенности реализации

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

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

Параметры:
deadline — абсолютное время, до которого следует ожидать
Возвращает:
false, если крайний срок наступил к моменту возврата; в противном случае — true
Выбрасывает:
InterruptedException — если текущий поток прерван (и поддерживается прерывание приостановки потока)

signal

void signal()
Пробуждает один ожидающий поток.

Если на этом условии ожидают какие-либо потоки, один из них выбирается для пробуждения. Затем этот поток должен повторно захватить блокировку, прежде чем метод await завершится.

Особенности реализации

Реализация может (и обычно так и делает) требовать, чтобы при вызове этого метода текущий поток удерживал блокировку, связанную с этим Condition. Реализации должны документировать это предусловие и действия, предпринимаемые, если блокировка не удерживается. Обычно выбрасывается исключение, например IllegalMonitorStateException.

signalAll

void signalAll()
Пробуждает все ожидающие потоки.

Если на этом условии ожидают какие-либо потоки, пробуждаются все они. Каждый поток должен повторно захватить блокировку, прежде чем сможет завершиться метод await.

Особенности реализации

Реализация может (и обычно так и делает) требовать, чтобы при вызове этого метода текущий поток удерживал блокировку, связанную с этим Condition. Реализации должны документировать это предусловие и действия, предпринимаемые, если блокировка не удерживается. Обычно выбрасывается исключение, например IllegalMonitorStateException.

Сообщить об ошибке или предложить улучшение
Дополнительные справочные материалы по API и документацию для разработчиков см. в разделе Документация Java SE, содержащем более подробные описания для разработчиков, обзоры концепций, определения терминов, обходные решения и примеры работающего кода. Другие версии.
Java является товарным знаком или зарегистрированным товарным знаком Oracle и/или её аффилированных лиц в США и других странах.
Авторское право © 1993, 2025, Oracle и/или её аффилированные лица, 500 Oracle Parkway, Redwood Shores, CA 94065 USA.
Все права защищены. Использование регулируется условиями лицензии и политикой распространения документации.

© 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://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/concurrent/locks/Condition.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API