Интерфейс Condition
- Все известные реализующие классы:
-
AbstractQueuedLongSynchronizer.ConditionObject,AbstractQueuedSynchronizer.ConditionObject
public interface Condition
Condition выделяет методы мониторинга объекта Object (wait, notify и notifyAll) в отдельные объекты, чтобы добиться эффекта нескольких наборов ожидания на один объект, комбинируя их с использованием произвольных реализаций Lock. Там, где Lock заменяет использование synchronized методов и инструкций, Condition заменяет использование методов мониторинга объекта. Условные переменные (также известные как очереди условного ожидания или условные переменные) предоставляют способ приостановки выполнения одного потока («ожидание»), пока другой поток не уведомит о том, что некоторое условие состояния может быть истинным. Поскольку доступ к этой общей информации о состоянии происходит в разных потоках, его необходимо защищать, поэтому с условной переменной связана блокировка. Ключевое свойство ожидания на условную переменную заключается в том, что она *атомарно* освобождает связанную блокировку и приостанавливает текущий поток, как и 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 |
awaitNanos |
Принуждает текущий поток ожидать, пока он не получит сигнал или не будет прерван, или не истечёт заданное время ожидания. |
void |
awaitUninterruptibly() |
Принуждает текущий поток ожидать, пока он не получит сигнал. |
boolean |
awaitUntil |
Принуждает текущий поток ожидать, пока он не получит сигнал или не будет прерван, или не истечёт заданный срок. |
void |
signal() |
Разбуждает один ожидающий поток. |
void |
signalAll() |
Разбуждает все ожидающие потоки. |
Методы
await
void await() throws InterruptedException
Блокировка, связанная с этим Condition, атомарно высвобождается, и текущий поток становится неактивным для планирования потоков и находится в состоянии ожидания, пока не произойдёт одно из четырёх событий:
- Другой поток вызывает метод
signal()для этогоCondition, и текущий поток выбирается в качестве потока, который должен быть разбужен; или - Другой поток вызывает метод
signalAll()для этогоCondition; или - Другой поток прерывает текущий поток, и поддержка прерывания приостановки потока включена; или
- Происходит «ложное пробуждение».
Во всех случаях, прежде чем метод сможет вернуть значение, текущий поток должен повторно получить блокировку, связанную с этим условием. Когда поток возвращается, он гарантированно держит эту блокировку.
Если текущий поток:
- имеет свой статус прерывания, установленный при входе в этот метод; или
- будет прерван во время ожидания, и поддержка прерывания приостановки потока включена,
InterruptedException, и статус прерывания текущего потока будет сброшен. В первом случае не оговаривается, происходит ли проверка прерывания до или после высвобождения блокировки. Соображения по реализации
Предполагается, что текущий поток держит блокировку, связанную с этим Condition, когда этот метод вызывается. Реализация должна определить, так ли это, и если нет, как на это реагировать. Обычно выбрасывается исключение (например, IllegalMonitorStateException), и реализация должна задокументировать этот факт.
Реализация может отдавать приоритет реагированию на прерывание по сравнению с нормальным возвратом метода в ответ на сигнал. В этом случае реализация должна гарантировать, что сигнал будет перенаправлен другому ожидающему потоку, если таковой имеется.
- Исключения:
-
InterruptedException- если текущий поток прерван (и поддержка прерывания приостановки потока включена)
awaitUninterruptibly
void awaitUninterruptibly()
Блокировка, связанная с этим условием, атомарно высвобождается, и текущий поток становится неактивным для планирования потоков и находится в состоянии ожидания, пока не произойдёт одно из трёх событий:
- Другой поток вызывает метод
signal()для этогоCondition, и текущий поток выбирается в качестве потока, который должен быть разбужен; или - Другой поток вызывает метод
signalAll()для этогоCondition; или - Происходит «ложное пробуждение».
Во всех случаях, прежде чем метод сможет вернуть значение, текущий поток должен повторно получить блокировку, связанную с этим условием. Когда поток возвращается, он гарантированно держит эту блокировку.
Если статус прерывания текущего потока установлен при входе в этот метод или поток прерывается во время ожидания, он будет продолжать ждать, пока не получит сигнал. Когда он, наконец, вернётся из этого метода, его статус прерывания по-прежнему будет установлен.
Соображения по реализации
Предполагается, что текущий поток держит блокировку, связанную с этим Condition, когда этот метод вызывается. Реализация должна определить, так ли это, и если нет, как на это реагировать. Обычно выбрасывается исключение (например, IllegalMonitorStateException), и реализация должна задокументировать этот факт.
awaitNanos
long awaitNanos(long nanosTimeout) throws InterruptedException
Блокировка, связанная с этим условием, атомарно высвобождается, и текущий поток становится неактивным для планирования потоков и находится в состоянии ожидания, пока не произойдёт одно из пяти событий:
- Другой поток вызывает метод
signal()для этогоCondition, и текущий поток выбирается в качестве потока, который должен быть разбужен; или - Другой поток вызывает метод
signalAll()для этогоCondition; или - Другой поток прерывает текущий поток, и поддержка прерывания приостановки потока включена; или
- Истекает заданное время ожидания; или
- Происходит «ложное пробуждение».
Во всех случаях, прежде чем метод сможет вернуть значение, текущий поток должен повторно получить блокировку, связанную с этим условием. Когда поток возвращается, он гарантированно держит эту блокировку.
Если текущий поток:
- имеет свой статус прерывания, установленный при входе в этот метод; или
- будет прерван во время ожидания, и поддержка прерывания приостановки потока включена,
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
Блокировка, связанная с этим условием, атомарно освобождается, и текущий поток отключается для целей планирования потоков и находится в ожидании, пока не произойдёт одно из пяти событий:
- Другой поток вызывает метод
signal()для этогоCondition, и текущий поток выбирается как поток, который будет разбужен; или - Другой поток вызывает метод
signalAll()для этогоCondition; или - Другой поток прерывает текущий поток, и поддержка прерывания приостановки потока реализована; или
- Истекает заданный срок ожидания; или
- Происходит «ложное пробуждение».
Во всех случаях, прежде чем этот метод может вернуть значение, текущий поток должен повторно получить блокировку, связанную с этим условием. Когда поток возвращает значение, он гарантированно держит эту блокировку.
Если текущий поток:
- имеет установленный статус прерывания при входе в этот метод; или
- прерывается во время ожидания и поддержка прерывания приостановки потока реализована,
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.
© 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/locks/Condition.html