Ответы:
Когда несколько потоков необходимо проверить и изменить логическое значение. Например:
if (!initialized) {
initialize();
initialized = true;
}
Это не потокобезопасно. Вы можете исправить это с помощью AtomicBoolean
:
if (atomicInitialized.compareAndSet(false, true)) {
initialize();
}
true
когда он initialize()
еще не завершен. Таким образом, это работает, только если другие потоки не заботятся о завершении initialize()
.
initialized
он просто используется для обеспечения того, чтобы один и только один поток вызывал initialize()
метод. Очевидно, initialized
что истинность не означает, что инициализация определенно завершена в этом случае, поэтому, возможно, немного другой термин будет лучше здесь. Опять же, это зависит от того, для чего он используется.
volatile boolean
бы так же, как AtomicBoolean
?
synchronized
блока, в этом случае вам больше не нужен AtomicBoolean
, просто a volatile boolean
. ( if(! this.initialized) { synchronized(this) { if(! this.initialized) { initialize(); this.initialized = true; } } }
будет гарантировать, что вызовет только один поток initialize
, и что все остальные потоки ждут, пока он это initialized
volatile
Вот заметки (из книги Брайана Гетца ), которые я сделал, которые могут быть вам полезны
Классы AtomicXXX
обеспечить неблокирующую реализацию Compare-And-Swap
Использует аппаратную поддержку (инструкция CMPXCHG для Intel). Когда через ваш код выполняется множество потоков, использующих эти API-интерфейсы атомарного параллелизма, они будут масштабироваться намного лучше, чем код, использующий мониторы / синхронизацию на уровне объектов. Поскольку механизмы синхронизации Java заставляют код ждать, когда в критических секциях выполняется множество потоков, значительное количество процессорного времени затрачивается на управление самим механизмом синхронизации (ожидание, уведомление и т. Д.). Поскольку новый API использует конструкции аппаратного уровня (атомарные переменные) и алгоритмы ожидания и блокировки для реализации безопасности потоков, гораздо больше процессорного времени затрачивается на «выполнение задач», а не на управление синхронизацией.
они не только обеспечивают лучшую пропускную способность, но и обеспечивают большую устойчивость к таким проблемам, как тупик и инверсия приоритетов.
Есть две основные причины, по которым вы можете использовать атомное логическое значение. Во-первых, он может быть изменён, вы можете передать его как ссылку и изменить значение, связанное, например, с самим логическим значением.
public final class MyThreadSafeClass{
private AtomicBoolean myBoolean = new AtomicBoolean(false);
private SomeThreadSafeObject someObject = new SomeThreadSafeObject();
public boolean doSomething(){
someObject.doSomeWork(myBoolean);
return myBoolean.get(); //will return true
}
}
и в классе someObject
public final class SomeThreadSafeObject{
public void doSomeWork(AtomicBoolean b){
b.set(true);
}
}
Что еще более важно, его потокобезопасность и может указывать разработчикам, поддерживающим класс, что эта переменная, как ожидается, будет изменена и прочитана из нескольких потоков. Если вы не используете AtomicBoolean, вы должны синхронизировать булеву переменную, которую вы используете, объявив ее энергозависимой или синхронизируя чтение и запись поля.
AtomicBoolean
Класс дает логическое значение , которое вы можете обновить атомарно. Используйте его, когда у нескольких потоков есть доступ к логической переменной.
Обзор пакета java.util.concurrent.atomic дает хорошее общее описание того, что делают классы в этом пакете и когда их использовать. Я бы также порекомендовал книгу Брайана Гетца « Практический параллелизм Java» .
Выдержка из описания пакета
Пакет java.util.concurrent.atomic description: Небольшой инструментарий классов, поддерживающий безоблокировочное поточно-ориентированное программирование для отдельных переменных. [...]
Спецификации этих методов позволяют реализациям использовать эффективные атомарные инструкции машинного уровня, доступные на современных процессорах. [...]
Экземпляры классов AtomicBoolean, AtomicInteger, AtomicLong и AtomicReference каждый обеспечивают доступ и обновления к одной переменной соответствующего типа. [...]
Эффекты памяти для доступа и обновления атомных элементов обычно следуют правилам для летучих компонентов:
- get имеет эффект памяти чтения изменчивой переменной.
- set имеет эффект памяти записи (присваивания) переменной переменной.
- weakCompareAndSet атомарно читает и условно записывает переменную, упорядочивается по отношению к другим операциям памяти с этой переменной, но в остальном действует как обычная операция энергонезависимой памяти.
- CompareAndSet и все другие операции чтения и обновления, такие как getAndIncrement, имеют эффект памяти как чтения, так и записи изменчивых переменных.
volatile boolean
vsAtomicBoolean
: stackoverflow.com/questions/3786825/…