Класс 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() сообщает, удерживается ли синхронизация исключительно текущим потоком, метод release(int), вызываемый со значением текущего getState() полностью освобождает этот объект, и acquire(java.util.concurrent.locks.AbstractQueuedSynchronizer.Node, int, boolean, boolean, boolean, long), учитывая это сохраненное значение состояния, в конечном итоге восстанавливает этот объект в его предыдущее состояние приобретения. Ни один 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 |
Реализация условия для AbstractQueuedSynchronizer, служащего основой для реализации Lock. |
Краткое описание конструкторов
| Модификатор | Конструктор | Описание |
|---|---|---|
protected |
Создаёт новый экземпляр AbstractQueuedSynchronizer с начальным состоянием синхронизации ноль. |
Краткое описание методов
| Модификатор и тип | Метод | Описание |
|---|---|---|
final void |
acquire |
Получение в эксклюзивном режиме, игнорируя прерывания. |
final void |
acquireInterruptibly |
Получение в эксклюзивном режиме, прерывая, если поток прерван. |
final void |
acquireShared |
Получение в совместном режиме, игнорируя прерывания. |
final void |
acquireSharedInterruptibly |
Получение в совместном режиме, прерывая, если поток прерван. |
protected final boolean |
compareAndSetState |
Атомарно устанавливает состояние синхронизации на заданное обновлённое значение, если текущее значение состояния равно ожидаемому значению. |
final Collection<Thread> |
getExclusiveQueuedThreads() |
Возвращает коллекцию потоков, которые могут ожидать получения в эксклюзивном режиме. |
final Thread |
getFirstQueuedThread() |
Возвращает первый (самый долго ожидающий) поток в очереди или null, если в очереди нет потоков. |
final Collection<Thread> |
getQueuedThreads() |
Возвращает коллекцию потоков, которые могут ожидать получения. |
final int |
getQueueLength() |
Возвращает оценку числа потоков, ожидающих получения. |
final Collection<Thread> |
getSharedQueuedThreads() |
Возвращает коллекцию потоков, которые могут ожидать получения в совместном режиме. |
protected final int |
getState() |
Возвращает текущее значение состояния синхронизации. |
final Collection<Thread> |
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 |
Попытка установить состояние, отражающее освобождение в совместном режиме. |
Методы, объявленные в классе java.util.concurrent.locks.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)
Этот метод всегда вызывается нитью, выполняющей получение. Если этот метод сообщает об ошибке, метод получения может поместить нить в очередь, если она ещё не в очереди, до тех пор, пока она не будет сигнализирована методом release другой нитью. Это можно использовать для реализации метода Lock.tryLock().
По умолчанию реализация выбрасывает UnsupportedOperationException.
- Параметры:
-
arg- аргумент получения. Это значение всегда то, которое передаётся методу получения или значение, сохранённое при входе в ожидание условия. Значение не интерпретируется и может представлять что угодно. - Возвращает:
-
trueв случае успеха. При успехе этот объект получен. - Исключения:
-
IllegalMonitorStateException- если получение поместит этот синхронизатор в недопустимое состояние. Это исключение должно выбрасываться последовательно, чтобы синхронизация работала правильно. -
UnsupportedOperationException- если эксклюзивный режим не поддерживается
tryRelease
protected boolean tryRelease(int arg)
Этот метод всегда вызывается нитью, выполняющей освобождение.
По умолчанию реализация выбрасывает UnsupportedOperationException.
- Параметры:
-
arg- аргумент освобождения. Это значение всегда то, которое передаётся методу освобождения или текущее значение состояния при входе в ожидание условия. Значение не интерпретируется и может представлять что угодно. - Возвращает:
-
trueесли этот объект теперь находится в полностью освобождённом состоянии, так что любые ожидающие нити могут попытаться получить его; иfalseв противном случае. - Исключения:
-
IllegalMonitorStateException- если освобождение поместит этот синхронизатор в недопустимое состояние. Это исключение должно выбрасываться последовательно, чтобы синхронизация работала правильно. -
UnsupportedOperationException- если эксклюзивный режим не поддерживается
isHeldExclusively
protected boolean isHeldExclusively()
true true, если синхронизация удерживается эксклюзивно с точки зрения текущей (вызывающей) нити. Этот метод вызывается при каждом вызове метода AbstractQueuedSynchronizer.ConditionObject. По умолчанию реализация выбрасывает UnsupportedOperationException. Этот метод вызывается внутренне только в методах AbstractQueuedSynchronizer.ConditionObject, поэтому не нужно определять, если условия не используются.
- Возвращает:
-
truetrue, если синхронизация удерживается эксклюзивно;falsefalse, иначе - Исключения:
-
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- максимальное количество наносекунд ожидания - Возвращает:
-
truetrue, если получено;falsefalse, если истекло время - Исключения:
-
InterruptedException- если текущая нить прервана
release
public final boolean release(int arg)
tryRelease(int) возвращает true. Этот метод может быть использован для реализации метода Lock.unlock().- Parameters:
-
arg- аргумент выпуска. Это значение передаётся вtryRelease(int), но в остальном не интерпретируется и может представлять собой что угодно. - Returns:
- значение, возвращённое из
tryRelease(int)
hasQueuedThreads
public final boolean hasQueuedThreads()
true не гарантирует, что какая-либо другая нить когда-либо получит доступ.- Returns:
-
trueесли могут существовать другие ожидающие нити
hasContended
public final boolean hasContended()
В этой реализации эта операция выполняется за постоянное время.
- Returns:
-
trueесли когда-либо была конкуренция
getFirstQueuedThread
public final Thread getFirstQueuedThread()
null если в данный момент нет нитей в очереди. В этой реализации эта операция обычно выполняется за постоянное время, но может быть итерационной при конфликте, если другие нити одновременно изменяют очередь.
- Returns:
- первую (самую долго ожидающую) нить в очереди, или
nullесли в данный момент нет нитей в очереди
isQueued
public final boolean isQueued(Thread thread)
Эта реализация обходит очередь, чтобы определить наличие данной нити.
- Parameters:
-
thread- нить - Returns:
-
trueесли данная нить находится в очереди - Throws:
-
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
}
}
- Returns:
-
trueесли в очереди есть нить, ожидающая приобретения до текущей нити, иfalseесли текущая нить находится в голове очереди или очередь пуста - Since:
- 1.7
getQueueLength
public final int getQueueLength()
- Returns:
- оценка количества ожидающих нитей
getQueuedThreads
public final Collection<Thread> getQueuedThreads()
- Returns:
- коллекция нитей
getExclusiveQueuedThreads
public final Collection<Thread> getExclusiveQueuedThreads()
getQueuedThreads(), за исключением того, что он возвращает только те нити, которые ожидают из-за приобретения в режиме исключительного доступа.- Returns:
- коллекция нитей
toString
public String toString()
"State =" за которой следует текущее значение getState(), и либо "nonempty" или "empty" в зависимости от того, пуста ли очередь.- Overrides:
-
toStringв классеObject - Returns:
- строка, идентифицирующая этот синхронизатор, а также его состояние
owns
public final boolean owns(AbstractQueuedSynchronizer.ConditionObject condition)
- Parameters:
-
condition- условие - Returns:
-
trueесли принадлежит - Throws:
-
NullPointerException- если условие равно null
hasWaiters
public final boolean hasWaiters(AbstractQueuedSynchronizer.ConditionObject condition)
true не гарантирует, что в будущем signal разбудит какие-либо потоки. Этот метод предназначен в первую очередь для мониторинга состояния системы.- Parameters:
-
condition- условие - Returns:
-
true, если есть ожидающие потоки - Throws:
-
IllegalMonitorStateException- если эксклюзивная синхронизация не выполняется -
IllegalArgumentException- если заданное условие не связано с этим синхронизатором -
NullPointerException- если условие равно null
getWaitQueueLength
public final int getWaitQueueLength(AbstractQueuedSynchronizer.ConditionObject condition)
- Parameters:
-
condition- условие - Returns:
- приблизительное количество ожидающих потоков
- Throws:
-
IllegalMonitorStateException- если эксклюзивная синхронизация не выполняется -
IllegalArgumentException- если заданное условие не связано с этим синхронизатором -
NullPointerException- если условие равно null
getWaitingThreads
public final Collection<Thread> getWaitingThreads(AbstractQueuedSynchronizer.ConditionObject condition)
- Parameters:
-
condition- условие - Returns:
- коллекция потоков
- Throws:
-
IllegalMonitorStateException- если эксклюзивная синхронизация не выполняется -
IllegalArgumentException- если заданное условие не связано с этим синхронизатором -
NullPointerException- если условие равно null
© 1993, 2021, 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/17/docs/api/java.base/java/util/concurrent/locks/AbstractQueuedSynchronizer.html