Класс 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 |
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 |
Попытка установить состояние, отражающее освобождение доступа в режиме совместного использования. |
Методы, объявленные в классе 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)
Этот метод всегда вызывается потоком, выполняющим приобретение. Если этот метод сообщает об ошибке, метод acquire может поместить поток в очередь, если он еще не в очереди, до тех пор, пока он не будет сигнализирован освобождением от другого потока. Это можно использовать для реализации метода Lock.tryLock().
Реализация по умолчанию выбрасывает UnsupportedOperationException.
- Параметры:
-
arg- аргумент приобретения. Это значение всегда то, которое передаётся методу acquire или сохраняется при входе в ожидание условия. В противном случае значение не интерпретируется и может представлять что угодно. - Возвращает:
-
trueв случае успеха. При успехе этот объект приобретён. - Исключения:
-
IllegalMonitorStateException- если приобретение поместит этот синхронизатор в недопустимое состояние. Это исключение должно выбрасываться последовательно, чтобы синхронизация работала правильно. -
UnsupportedOperationException- если эксклюзивный режим не поддерживается
tryRelease
protected boolean tryRelease(int arg)
Этот метод всегда вызывается потоком, выполняющим освобождение.
Реализация по умолчанию выбрасывает UnsupportedOperationException.
- Параметры:
-
arg- аргумент освобождения. Это значение всегда то, которое передаётся методу release или текущее значение состояния при входе в ожидание условия. В противном случае значение не интерпретируется и может представлять что угодно. - Возвращает:
-
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().- 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, из-за того, что очередь пуста.
Этот метод предназначен для использования в справедливом синхронизаторе, чтобы избежать barging. Такой синхронизатор должен возвращать 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, 2023, 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/21/docs/api/java.base/java/util/concurrent/locks/AbstractQueuedSynchronizer.html