Пакет java.util.concurrent.atomic
Небольшой набор классов, поддерживающих потокобезопасное программирование без блокировок на отдельных переменных.
См.: Описание
| Класс | Описание |
|---|---|
| AtomicBoolean | Значение типа |
| AtomicInteger | Значение типа |
| AtomicIntegerArray | Массив типа |
| AtomicIntegerFieldUpdater<T> | Утилита на основе рефлексии, которая позволяет атомарно обновлять указанные |
| AtomicLong | Значение типа |
| AtomicLongArray | Массив типа |
| AtomicLongFieldUpdater<T> | Утилита на основе рефлексии, которая позволяет атомарно обновлять указанные |
| AtomicMarkableReference<V> | Тип |
| AtomicReference<V> | Ссылка на объект, которая может обновляться атомарно. |
| AtomicReferenceArray<E> | Массив ссылок на объекты, в котором элементы могут обновляться атомарно. |
| AtomicReferenceFieldUpdater<T,V> | Утилита на основе рефлексии, которая позволяет атомарно обновлять указанные |
| AtomicStampedReference<V> | Тип |
| DoubleAccumulator | Одна или несколько переменных, которые вместе поддерживают текущее |
| DoubleAdder | Одна или несколько переменных, которые вместе поддерживают начальную сумму |
| LongAccumulator | Одна или несколько переменных, которые вместе поддерживают текущее |
| LongAdder | Одна или несколько переменных, которые вместе поддерживают начальную сумму |
Описание пакета java.util.concurrent.atomic
Небольшой набор классов, поддерживающих потокобезопасное программирование без блокировок на отдельных переменных. По сути, классы в этом пакете расширяют понятие volatile значений, полей и элементов массивов до тех, которые также обеспечивают атомарную условную операцию обновления вида:
boolean compareAndSet(expectedValue, updateValue);
Этот метод (типы аргументов которого меняются в разных классах) атомарно устанавливает переменную в updateValue значение, если она в настоящее время содержит expectedValue, сообщая true об успехе. Классы в этом пакете также содержат методы для получения и безусловного установки значений, а также более слабую условную атомарную операцию обновления weakCompareAndSet описанную ниже.
Спецификации этих методов позволяют реализациям использовать эффективные атомарные инструкции на уровне машины, доступные на современных процессорах. Однако на некоторых платформах поддержка может потребовать некоторой формы внутренней блокировки. Таким образом, методы не гарантируют, что они будут строго неблокирующими - поток может временно заблокироваться перед выполнением операции.
Экземпляры классов AtomicBoolean, AtomicInteger, AtomicLong и AtomicReference каждый предоставляют доступ и обновления к одной переменной соответствующего типа. Каждый класс также предоставляет соответствующие вспомогательные методы для этого типа. Например, классы AtomicLong и AtomicInteger предоставляют атомарные методы инкремента. Одно из применений - генерация номеров последовательности, как в:
class Sequencer {
private final AtomicLong sequenceNumber
= new AtomicLong(0);
public long next() {
return sequenceNumber.getAndIncrement();
}
} Несложно определить новые вспомогательные функции, которые, подобно getAndIncrement, применяют функцию к значению атомарно. Например, задана некоторая трансформация
long transform(long input)напишите ваш вспомогательный метод следующим образом:
long getAndTransform(AtomicLong var) {
long prev, next;
do {
prev = var.get();
next = transform(prev);
} while (!var.compareAndSet(prev, next));
return prev; // return next; for transformAndGet
} Эффекты памяти для обращений и обновлений атомных переменных обычно следуют правилам для переменных volatile, как указано в Спецификации языка Java (17.4 Модель памяти):
-
getимеет эффекты памяти чтения переменнойvolatile. -
setимеет эффекты памяти записи (присваивания) переменнойvolatile. -
lazySetимеет эффекты памяти записи (присваивания) переменнойvolatile, за исключением того, что он допускает перестановки с последующими (но не предыдущими) действиями памяти, которые сами не накладывают ограничений на перестановки с обычными не-volatileоперациями записи. Среди других контекстов использования,lazySetможет применяться при обнулении, для сбора мусора, ссылки, которая больше никогда не используется. -
weakCompareAndSetатомарно читает и условно записывает переменную, но не создает никаких порядков «происходит-раньше», так что не предоставляет никаких гарантий относительно предыдущих или последующих чтений и записей любых переменных, кроме целиweakCompareAndSet. -
compareAndSetи все другие операции чтения и обновления, такие какgetAndIncrementимеют эффекты памяти как чтения, так и записиvolatileпеременных.
В дополнение к классам, представляющим отдельные значения, этот пакет содержит классы Updater, которые могут использоваться для получения compareAndSet операций над любым выбранным volatile полем любого выбранного класса. AtomicReferenceFieldUpdater, AtomicIntegerFieldUpdater и AtomicLongFieldUpdater - утилиты на основе рефлексии, которые предоставляют доступ к соответствующим типам полей. Они в основном полезны в атомарных структурах данных, в которых несколько volatile полей одного узла (например, ссылки узла дерева) независимо подвергаются атомарным обновлениям. Эти классы обеспечивают большую гибкость в том, как и когда использовать атомарные обновления, ценой более неуклюжей настройки на основе рефлексии, менее удобного использования и более слабых гарантий.
Классы AtomicIntegerArray, AtomicLongArray и AtomicReferenceArray дополнительно расширяют поддержку атомарных операций до массивов этих типов. Эти классы также примечательны тем, что предоставляют volatile семантику доступа к элементам массива, которая не поддерживается для обычных массивов.
Атомарные классы также поддерживают метод weakCompareAndSet, который имеет ограниченное применение. На некоторых платформах слабая версия может быть более эффективной, чем compareAndSet в нормальном случае, но отличается тем, что любое обращение к методу weakCompareAndSet может вернуть false случайно (то есть без видимой причины). Возвращаемое значение false означает только то, что операция может быть повторена, если это необходимо, опираясь на гарантию, что многократное обращение, когда переменная содержит expectedValue и никакой другой поток также не пытается установить переменную, в конечном итоге приведет к успеху. (Такие случайные неудачи могут, например, быть вызваны эффектами конкуренции в памяти, которые не связаны с тем, равны ли ожидаемое и текущее значения.) Кроме того, weakCompareAndSet не предоставляет гарантии порядка, которые обычно необходимы для управления синхронизацией. Однако этот метод может быть полезен для обновления счетчиков и статистики, когда такие обновления не связаны с другими порядками «происходит-раньше» программы. Когда поток видит обновление атомарной переменной, вызванное weakCompareAndSet, он не обязательно видит обновления любых других переменных, произошедших до weakCompareAndSet. Это может быть приемлемо, например, при обновлении статистических данных о производительности, но редко в других случаях.
Класс AtomicMarkableReference связывает единственный булевый тип с ссылкой. Например, этот бит может использоваться внутри структуры данных, чтобы означать, что объект, на который ссылаются, логически был удален. Класс AtomicStampedReference связывает целочисленное значение со ссылкой. Это может использоваться, например, для представления номеров версий, соответствующих сериям обновлений.
Атомарные классы разработаны в первую очередь как строительные блоки для реализации неблокирующих структур данных и связанных инфраструктурных классов. Метод compareAndSet не является универсальной заменой блокировок. Он применяется только тогда, когда критические обновления объекта ограничены одной переменной.
Атомарные классы не являются универсальными заменителями java.lang.Integer и родственных классов. Они не определяют методы, такие как equals, hashCode и compareTo. (Поскольку атомарные переменные предполагаются изменяемыми, они являются плохими кандидатами для ключей хэш-таблицы.) Кроме того, классы предоставляются только для тех типов, которые обычно полезны в целевых приложениях. Например, нет атомарного класса для представления byte. В тех редких случаях, когда вы хотите это сделать, вы можете использовать AtomicInteger для хранения byte значений и выполнить соответствующее приведение типов. Вы также можете хранить числа с плавающей запятой, используя преобразования Float.floatToRawIntBits(float) и Float.intBitsToFloat(int), а числа с двойной точностью - используя преобразования Double.doubleToRawLongBits(double) и Double.longBitsToDouble(long).
- С тех пор:
- 1.5
© 1993, 2020, 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.