Класс AbstractQueuedSynchronizer
- Все реализуемые интерфейсы:
Serializable
public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements Serializable
int для представления состояния. Подклассы должны определять защищённые методы, изменяющие это состояние и определяющие, что оно означает с точки зрения захвата или освобождения данного объекта. На этой основе остальные методы этого класса выполняют все операции постановки в очередь и блокировки. Подклассы могут поддерживать другие поля состояния, однако в отношении синхронизации отслеживается только атомарно обновляемое значение int, изменяемое с помощью методов getState(), setState(int) и compareAndSetState(int, int). Подклассы следует объявлять как непубличные внутренние вспомогательные классы, используемые для реализации свойств синхронизации охватывающего их класса. Класс AbstractQueuedSynchronizer не реализует никаких интерфейсов синхронизации. Вместо этого он определяет такие методы, как acquireInterruptibly(int), которые конкретные блокировки и связанные с ними средства синхронизации могут вызывать по мере необходимости для реализации своих открытых методов.
Этот класс поддерживает один или оба режима: эксклюзивный режим по умолчанию и разделяемый режим. При захвате в эксклюзивном режиме попытки захвата со стороны других потоков не могут завершиться успешно. В разделяемом режиме захват несколькими потоками может завершиться успешно, но это не обязательно. Этот класс не «понимает» различий между этими режимами иначе, чем в механическом смысле: если попытка захвата в разделяемом режиме завершается успешно, следующий ожидающий поток (если он есть) также должен определить, может ли он выполнить захват. Ожидающие потоки в разных режимах используют одну FIFO-очередь. Обычно подклассы реализации поддерживают только один из этих режимов, однако оба режима могут использоваться, например, в ReadWriteLock. Подклассам, поддерживающим только эксклюзивный или только разделяемый режим, не нужно определять методы для неиспользуемого режима.
Этот класс определяет вложенный класс AbstractQueuedSynchronizer.ConditionObject, который может использоваться подклассами, поддерживающими эксклюзивный режим, в качестве реализации Condition, если метод isHeldExclusively() сообщает, удерживается ли блокировка синхронизации эксклюзивно текущим потоком, вызванный с текущим значением getState() метод release(int) полностью освобождает этот объект, а базовая версия acquire(int) в конечном счёте восстанавливает прежнее состояние захвата этого объекта, используя сохранённое значение состояния. Ни один метод AbstractQueuedSynchronizer не создаёт такое условие, поэтому не используйте его, если это ограничение не может быть выполнено. Поведение AbstractQueuedSynchronizer.ConditionObject, разумеется, зависит от семантики реализации средства синхронизации.
Этот класс предоставляет методы проверки, инструментирования и мониторинга внутренней очереди, а также аналогичные методы для объектов условий. При необходимости их можно экспортировать в классы, использующие AbstractQueuedSynchronizer для реализации механизмов синхронизации.
При сериализации этого класса сохраняется только базовое атомарное целое число, хранящее состояние, поэтому десериализованные объекты имеют пустые очереди потоков. Типичные подклассы, которым требуется поддержка сериализации, определяют метод readObject, восстанавливающий известное исходное состояние после десериализации.
Использование
Чтобы использовать этот класс в качестве основы для средства синхронизации, переопределите следующие методы, если это применимо, проверяя и/или изменяя состояние синхронизации с помощью getState(), setState(int) и/или compareAndSetState(int, int):
UnsupportedOperationException. Реализации этих методов должны быть потокобезопасными и, как правило, короткими и неблокирующими. Определение этих методов — единственный поддерживаемый способ использования данного класса. Все остальные методы объявлены как final, поскольку их нельзя изменять независимо. Также могут оказаться полезными унаследованные методы из AbstractOwnableSynchronizer, позволяющие отслеживать поток, владеющий эксклюзивным средством синхронизации. Рекомендуется использовать эти методы: они позволяют средствам мониторинга и диагностики определять, какие потоки удерживают блокировки.
Хотя этот класс основан на внутренней FIFO-очереди, он не обеспечивает автоматически политику захвата FIFO. Основная часть эксклюзивной синхронизации выглядит следующим образом:
Acquire:
while (!tryAcquire(arg)) {
enqueue thread if it is not already queued;
possibly block current thread;
}
Release:
if (tryRelease(arg))
unblock the first queued thread;
(Разделяемый режим устроен аналогично, но может включать каскадные сигналы.) Поскольку проверки при захвате выполняются до постановки в очередь, новый поток, пытающийся выполнить захват, может обойти другие заблокированные потоки, уже находящиеся в очереди. Однако при необходимости можно определить tryAcquire и/или tryAcquireShared, чтобы запретить обход, вызывая внутри один или несколько методов проверки и тем самым обеспечивая справедливый порядок захвата FIFO. В частности, большинство справедливых средств синхронизации могут определить tryAcquire так, чтобы он возвращал false, если hasQueuedPredecessors() (метод, специально предназначенный для использования справедливыми средствами синхронизации) возвращает true. Возможны и другие варианты.
Пропускная способность и масштабируемость обычно максимальны при использовании стратегии обхода по умолчанию (также называемой жадной, без отказа от борьбы и избегающей конвоев). Хотя такая стратегия не гарантирует справедливость или отсутствие голодания, потокам, раньше поставленным в очередь, разрешается повторно бороться за захват до более поздних потоков, и при каждой такой попытке у них есть равные шансы на успех по сравнению с вновь поступившими потоками. Кроме того, хотя при захвате в обычном смысле не выполняется «активное ожидание», перед блокировкой может производиться несколько вызовов tryAcquire, перемежающихся с другими вычислениями. Это обеспечивает большую часть преимуществ активного ожидания, когда эксклюзивная синхронизация удерживается лишь короткое время, не создавая при этом большей части сопутствующих проблем, если это не так. При желании это поведение можно дополнить проверками «быстрого пути» перед вызовами методов захвата, предварительно проверяя hasContended() и/или hasQueuedThreads(), чтобы выполнять их только в случае, когда средство синхронизации, вероятно, не испытывает конкуренции.
Этот класс обеспечивает эффективную и масштабируемую основу для синхронизации, в частности, ограничивая область применения средствами синхронизации, которые могут полагаться на состояние int, параметры захвата и освобождения и внутреннюю FIFO-очередь ожидания. Если этого недостаточно, можно создавать средства синхронизации на более низком уровне, используя классы atomic, собственные пользовательские классы Queue и средства блокировки LockSupport.
Примеры использования
Ниже приведён класс нерекурсивной блокировки взаимного исключения, в котором ноль обозначает незаблокированное состояние, а единица — заблокированное. Хотя нерекурсивная блокировка не требует строгой необходимости сохранять сведения о текущем потоке-владельце, этот класс делает это для упрощения мониторинга использования. Он также поддерживает условия и предоставляет некоторые методы инструментирования:
class Mutex implements Lock, java.io.Serializable {
// Our internal helper class
private static class Sync extends AbstractQueuedSynchronizer {
// Acquires the lock if state is zero
public boolean tryAcquire(int acquires) {
assert acquires == 1; // Otherwise unused
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
// Releases the lock by setting state to zero
protected boolean tryRelease(int releases) {
assert releases == 1; // Otherwise unused
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
setExclusiveOwnerThread(null);
setState(0);
return true;
}
// Reports whether in locked state
public boolean isLocked() {
return getState() != 0;
}
public boolean isHeldExclusively() {
// a data race, but safe due to out-of-thin-air guarantees
return getExclusiveOwnerThread() == Thread.currentThread();
}
// Provides a Condition
public Condition newCondition() {
return new ConditionObject();
}
// Deserializes properly
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException {
s.defaultReadObject();
setState(0); // reset to unlocked state
}
}
// The sync object does all the hard work. We just forward to it.
private final Sync sync = new Sync();
public void lock() { sync.acquire(1); }
public boolean tryLock() { return sync.tryAcquire(1); }
public void unlock() { sync.release(1); }
public Condition newCondition() { return sync.newCondition(); }
public boolean isLocked() { return sync.isLocked(); }
public boolean isHeldByCurrentThread() {
return sync.isHeldExclusively();
}
public boolean hasQueuedThreads() {
return sync.hasQueuedThreads();
}
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
} Ниже приведён класс защёлки, похожий на CountDownLatch, за исключением того, что для срабатывания ему требуется только один signal. Поскольку защёлка не является эксклюзивной, в ней используются методы захвата и освобождения shared.
class BooleanLatch {
private static class Sync extends AbstractQueuedSynchronizer {
boolean isSignalled() { return getState() != 0; }
protected int tryAcquireShared(int ignore) {
return isSignalled() ? 1 : -1;
}
protected boolean tryReleaseShared(int ignore) {
setState(1);
return true;
}
}
private final Sync sync = new Sync();
public boolean isSignalled() { return sync.isSignalled(); }
public void signal() { sync.releaseShared(1); }
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
}
- Начиная с версии:
- 1.5
- См. также:
Краткое описание вложенных классов
| Модификатор и тип | Класс | Описание |
|---|---|---|
class |
AbstractQueuedSynchronizer.ConditionObject |
Реализация Condition для AbstractQueuedSynchronizer, служащего основой для реализации Lock. |
Краткое описание конструкторов
| Модификатор | Конструктор | Описание |
|---|---|---|
protected |
Создаёт новый экземпляр AbstractQueuedSynchronizer с начальным состоянием синхронизации, равным нулю. |
Краткое описание методов
| Модификатор и тип | Метод | Описание |
|---|---|---|
final void |
acquire |
Выполняет захват в эксклюзивном режиме, игнорируя прерывания. |
final void |
acquireInterruptibly |
Выполняет захват в эксклюзивном режиме и прерывает операцию при прерывании потока. |
final void |
acquireShared |
Выполняет захват в разделяемом режиме, игнорируя прерывания. |
final void |
acquireSharedInterruptibly |
Выполняет захват в разделяемом режиме и прерывает операцию при прерывании потока. |
protected final boolean |
compareAndSetState |
Атомарно задаёт указанное новое состояние синхронизации, если текущее значение состояния равно ожидаемому. |
final Collection |
getExclusiveQueuedThreads() |
Возвращает коллекцию потоков, которые могут ожидать захвата в эксклюзивном режиме. |
final Thread |
getFirstQueuedThread() |
Возвращает первый поток в очереди (ожидающий дольше всех) или null, если в очереди сейчас нет потоков. |
final Collection |
getQueuedThreads() |
Возвращает коллекцию потоков, которые могут ожидать захвата. |
final int |
getQueueLength() |
Возвращает оценочное количество потоков, ожидающих захвата. |
final Collection |
getSharedQueuedThreads() |
Возвращает коллекцию потоков, которые могут ожидать захвата в разделяемом режиме. |
protected final int |
getState() |
Возвращает текущее значение состояния синхронизации. |
final Collection |
getWaitingThreads |
Возвращает коллекцию потоков, которые могут ожидать указанного условия, связанного с этим средством синхронизации. |
final int |
getWaitQueueLength |
Возвращает оценочное количество потоков, ожидающих указанного условия, связанного с этим средством синхронизации. |
final boolean |
hasContended() |
Проверяет, возникала ли когда-либо конкуренция между потоками при захвате этого средства синхронизации, то есть блокировался ли когда-либо метод захвата. |
final boolean |
hasQueuedPredecessors() |
Проверяет, ожидали ли какие-либо потоки захвата дольше, чем текущий поток. |
final boolean |
hasQueuedThreads() |
Проверяет, ожидают ли какие-либо потоки захвата. |
final boolean |
hasWaiters |
Проверяет, ожидают ли какие-либо потоки указанного условия, связанного с этим средством синхронизации. |
protected boolean |
isHeldExclusively() |
Возвращает true, если блокировка синхронизации удерживается эксклюзивно относительно текущего (вызывающего) потока. |
final boolean |
isQueued |
Возвращает true, если указанный поток в данный момент находится в очереди. |
final boolean |
owns |
Проверяет, использует ли указанный ConditionObject это средство синхронизации в качестве блокировки. |
final boolean |
release |
Выполняет освобождение в эксклюзивном режиме. |
final boolean |
releaseShared |
Выполняет освобождение в разделяемом режиме. |
protected final void |
setState |
Задаёт значение состояния синхронизации. |
String |
toString() |
Возвращает строку, идентифицирующую это средство синхронизации и его состояние. |
protected boolean |
tryAcquire |
Пытается выполнить захват в эксклюзивном режиме. |
final boolean |
tryAcquireNanos |
Пытается выполнить захват в эксклюзивном режиме; операция прерывается при прерывании потока и завершается неудачей по истечении указанного времени ожидания. |
protected int |
tryAcquireShared |
Пытается выполнить захват в разделяемом режиме. |
final boolean |
tryAcquireSharedNanos |
Пытается выполнить захват в разделяемом режиме; операция прерывается при прерывании потока и завершается неудачей по истечении указанного времени ожидания. |
protected boolean |
tryRelease |
Пытается установить состояние, соответствующее освобождению в эксклюзивном режиме. |
protected boolean |
tryReleaseShared |
Пытается установить состояние, соответствующее освобождению в разделяемом режиме. |
Методы, объявленные в классе AbstractOwnableSynchronizer
getExclusiveOwnerThread, setExclusiveOwnerThread
Подробное описание конструкторов
AbstractQueuedSynchronizer
protected AbstractQueuedSynchronizer()
AbstractQueuedSynchronizer с начальным состоянием синхронизации, равным нулю.Подробное описание методов
getState
protected final int getState()
volatile.- Возвращает:
- текущее значение состояния
setState
protected final void setState(int newState)
volatile.- Параметры:
-
newState— новое значение состояния
compareAndSetState
protected final boolean compareAndSetState(int expect, int update)
volatile.- Параметры:
-
expect— ожидаемое значение -
update— новое значение - Возвращает:
-
trueв случае успеха. Возврат значения false означает, что фактическое значение не совпадало с ожидаемым.
tryAcquire
protected boolean tryAcquire(int arg)
Этот метод всегда вызывается потоком, выполняющим захват. Если метод сообщает о неудаче, метод захвата может поместить поток в очередь, если он еще не находится в ней, пока поток не получит сигнал при освобождении другим потоком. Это можно использовать для реализации метода Lock.tryLock().
Реализация по умолчанию выбрасывает исключение UnsupportedOperationException.
- Параметры:
-
arg— аргумент захвата. Это значение всегда является значением, переданным методу захвата, или значением, сохраненным при входе в ожидание условия. В противном случае оно не интерпретируется и может представлять любые данные. - Возвращает:
-
trueв случае успеха. При успешном выполнении этот объект захвачен. - Исключения:
-
IllegalMonitorStateException— если захват привел бы синхронизатор в недопустимое состояние. Для корректной работы синхронизации это исключение должно выбрасываться согласованным образом. -
UnsupportedOperationException— если эксклюзивный режим не поддерживается
tryRelease
protected boolean tryRelease(int arg)
Этот метод всегда вызывается потоком, выполняющим освобождение.
Реализация по умолчанию выбрасывает исключение UnsupportedOperationException.
- Параметры:
-
arg— аргумент освобождения. Это значение всегда является значением, переданным методу освобождения, или текущим значением состояния при входе в ожидание условия. В противном случае оно не интерпретируется и может представлять любые данные. - Возвращает:
-
true, если теперь этот объект полностью освобожден, так что ожидающие потоки могут попытаться выполнить захват; иfalseв противном случае. - Исключения:
-
IllegalMonitorStateException— если освобождение привело бы синхронизатор в недопустимое состояние. Для корректной работы синхронизации это исключение должно выбрасываться согласованным образом. -
UnsupportedOperationException— если эксклюзивный режим не поддерживается
isHeldExclusively
protected boolean isHeldExclusively()
true, если синхронизация удерживается эксклюзивно относительно текущего (вызывающего) потока. Этот метод вызывается при каждом вызове метода AbstractQueuedSynchronizer.ConditionObject. Реализация по умолчанию выбрасывает исключение UnsupportedOperationException. Этот метод вызывается внутри только методами AbstractQueuedSynchronizer.ConditionObject, поэтому его не требуется определять, если условия не используются.
- Возвращает:
-
true, если синхронизация удерживается эксклюзивно;falseв противном случае - Исключения:
-
UnsupportedOperationException— если условия не поддерживаются
acquire
public final void acquire(int arg)
tryAcquire(int) по меньшей мере один раз и возвращает управление при успехе. В противном случае поток помещается в очередь и, возможно, неоднократно блокируется и разблокируется, вызывая tryAcquire(int) до достижения успеха. Этот метод можно использовать для реализации метода Lock.lock().- Параметры:
-
arg— аргумент захвата. Это значение передается вtryAcquire(int), но в остальном не интерпретируется и может представлять любые данные.
acquireInterruptibly
public final void acquireInterruptibly(int arg) throws InterruptedException
tryAcquire(int) по меньшей мере один раз; при успехе метод возвращает управление. В противном случае поток помещается в очередь и, возможно, неоднократно блокируется и разблокируется, вызывая tryAcquire(int) до достижения успеха или прерывания потока. Этот метод можно использовать для реализации метода Lock.lockInterruptibly().- Параметры:
-
arg— аргумент захвата. Это значение передается вtryAcquire(int), но в остальном не интерпретируется и может представлять любые данные. - Исключения:
-
InterruptedException— если текущий поток прерван
tryAcquireNanos
public final boolean tryAcquireNanos(int arg, long nanosTimeout) throws InterruptedException
tryAcquire(int) по меньшей мере один раз; при успехе метод возвращает управление. В противном случае поток помещается в очередь и, возможно, неоднократно блокируется и разблокируется, вызывая tryAcquire(int) до достижения успеха, прерывания потока или истечения времени ожидания. Этот метод можно использовать для реализации метода Lock.tryLock(long, TimeUnit).- Параметры:
-
arg— аргумент захвата. Это значение передается вtryAcquire(int), но в остальном не интерпретируется и может представлять любые данные. -
nanosTimeout— максимальное время ожидания в наносекундах - Возвращает:
-
true, если захват выполнен;false, если время ожидания истекло - Исключения:
-
InterruptedException— если текущий поток прерван
release
public final boolean release(int arg)
tryRelease(int) возвращает true, один или несколько потоков разблокируются. Этот метод можно использовать для реализации метода Lock.unlock().- Параметры:
-
arg— аргумент освобождения. Это значение передается вtryRelease(int), но в остальном не интерпретируется и может представлять любые данные. - Возвращает:
- значение, возвращенное методом
tryRelease(int)
hasQueuedThreads
public final boolean hasQueuedThreads()
true не гарантирует, что какой-либо другой поток когда-либо выполнит захват.- Возвращает:
-
true, если другие потоки могут ожидать выполнения захвата
hasContended
public final boolean hasContended()
В данной реализации эта операция выполняется за постоянное время.
- Возвращает:
-
true, если когда-либо возникала конкуренция
getFirstQueuedThread
public final Thread getFirstQueuedThread()
null, если в очереди сейчас нет потоков. В данной реализации эта операция обычно выполняется за постоянное время, но при конкуренции может потребоваться обход очереди, если другие потоки одновременно изменяют ее.
- Возвращает:
- первый (дольше всех ожидающий) поток в очереди или
null, если в очереди сейчас нет потоков
isQueued
public final boolean isQueued(Thread thread)
Эта реализация обходит очередь, чтобы определить, присутствует ли в ней указанный поток.
- Параметры:
-
thread— поток - Возвращает:
-
true, если указанный поток находится в очереди - Исключения:
-
NullPointerException— если поток равен null
hasQueuedPredecessors
public final boolean hasQueuedPredecessors()
Вызов этого метода эквивалентен следующему (но может быть эффективнее):
getFirstQueuedThread() != Thread.currentThread()
&& hasQueuedThreads() Следует учитывать, что отмена ожидания из-за прерываний и тайм-аутов может произойти в любой момент, поэтому результат true не гарантирует, что какой-либо другой поток выполнит захват раньше текущего. Также другой поток может опередить текущий поток и добавить себя в очередь после того, как этот метод вернет false, поскольку очередь пуста.
Этот метод предназначен для использования справедливым синхронизатором во избежание обгона. Метод tryAcquire(int) такого синхронизатора должен возвращать false, а его метод tryAcquireShared(int) должен возвращать отрицательное значение, если этот метод возвращает true (кроме случаев повторного входящего захвата). Например, метод
tryAcquire справедливого реентерабельного синхронизатора эксклюзивного режима может выглядеть так:
protected boolean tryAcquire(int arg) {
if (isHeldExclusively()) {
// A reentrant acquire; increment hold count
return true;
} else if (hasQueuedPredecessors()) {
return false;
} else {
// try to acquire normally
}
}
- Возвращает:
-
true, если в очереди перед текущим потоком находится другой поток, иfalse, если текущий поток находится в начале очереди или очередь пуста - С версии:
- 1.7
getQueueLength
public final int getQueueLength()
- Возвращает:
- оценочное количество потоков, ожидающих выполнения захвата
getQueuedThreads
public final Collection<Thread> getQueuedThreads()
- Возвращает:
- коллекцию потоков
getExclusiveQueuedThreads
public final Collection<Thread> getExclusiveQueuedThreads()
getQueuedThreads(), за исключением того, что возвращает только потоки, ожидающие выполнения эксклюзивного захвата.- Возвращает:
- коллекцию потоков
toString
public String toString()
"State =", за которой следует текущее значение getState(), а также "nonempty" или "empty" в зависимости от того, пуста ли очередь.owns
public final boolean owns(AbstractQueuedSynchronizer.ConditionObject condition)
- Параметры:
-
condition— условие - Возвращает:
-
true, если условие принадлежит этому синхронизатору - Исключения:
-
NullPointerException— если условие равно null
hasWaiters
public final boolean hasWaiters(AbstractQueuedSynchronizer.ConditionObject condition)
true не гарантирует, что последующий вызов signal разбудит какие-либо потоки. Этот метод предназначен главным образом для мониторинга состояния системы.- Параметры:
-
condition— условие - Возвращает:
-
true, если есть ожидающие потоки - Исключения:
-
IllegalMonitorStateException— если эксклюзивная синхронизация не удерживается -
IllegalArgumentException— если указанное условие не связано с этим синхронизатором -
NullPointerException— если условие равно null
getWaitQueueLength
public final int getWaitQueueLength(AbstractQueuedSynchronizer.ConditionObject condition)
- Параметры:
-
condition— условие - Возвращает:
- оценочное количество ожидающих потоков
- Исключения:
-
IllegalMonitorStateException— если эксклюзивная синхронизация не удерживается -
IllegalArgumentException— если указанное условие не связано с этим синхронизатором -
NullPointerException— если условие равно null
getWaitingThreads
public final Collection<Thread> getWaitingThreads(AbstractQueuedSynchronizer.ConditionObject condition)
- Параметры:
-
condition— условие - Возвращает:
- коллекцию потоков
- Исключения:
-
IllegalMonitorStateException— если эксклюзивная синхронизация не удерживается -
IllegalArgumentException— если указанное условие не связано с этим синхронизатором -
NullPointerException— если условие равно null
© 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/AbstractQueuedSynchronizer.html