Коли мені потрібно використовувати AtomicBoolean на Java?


Відповіді:


244

Коли кілька потоків потрібно перевірити і змінити булеву форму. Наприклад:

if (!initialized) {
   initialize();
   initialized = true;
}

Це не є безпечним для потоків. Ви можете виправити це за допомогою AtomicBoolean:

if (atomicInitialized.compareAndSet(false, true)) {
    initialize();
}

51
Це не схоже на приклад у реальному світі - інший потік може бачити, trueколи initialize()його не завершено. Отже, це працює лише в тому випадку, якщо інші теми не дбають про завершення initialize().
axtavt

6
@axtavt: Я думаю, що це цілком справедливий приклад у реальному світі, якщо initializedйого просто використовують для того, щоб один і лише один потік викликав initialize()метод. Очевидно, initializedщо правда не означає, що в цьому випадку ініціалізація точно закінчилася, тому, можливо, тут буде трохи інший термін. Знову ж таки, це залежить від того, для чого він використовується.
ColinD

14
вам знадобляться 2 булевих символи для initStarted та initCompleted, тоді перша нитка встановлюється initStarted і викликає Initiise (), решта чекайте, поки initCompleted буде правдою.
Мартін

3
@Bozho - читання і запис в булевих полів атомне право?, Тепер, летючий дає мені останню значення логічного поля. Отже, фактично, це не volatile booleanбуло б як AtomicBoolean?.
TheLostMind

2
@Martin: Немає прямого способу дочекатися, коли булева стати справжньою; потрібні додаткові механізми. Найрозумніший підхід - використовувати synchronizedблок, і в цьому випадку вам більше не потрібен AtomicBoolean, а просто volatile boolean. ( if(! this.initialized) { synchronized(this) { if(! this.initialized) { initialize(); this.initialized = true; } } }забезпечить виклик лише одного потоку initialize, і всі інші потоки чекають його, якщо initializedце позначено volatile.)
ruakh

52

Ось замітки (з книги Брайана Геца ), які я зробив, які можуть вам допомогти

Класи AtomicXXX

  • забезпечити неблокуючу реалізацію порівняння та заміни

  • Користується технічною підтримкою (інструкція CMPXCHG для Intel) Коли через ваш код використовується багато потоків, що використовує цей атомний API паралельності, вони будуть масштабуватися набагато краще, ніж код, який використовує монітори / синхронізацію рівня об'єктів. Оскільки механізми синхронізації Java змушують код чекати, коли через ваші критичні розділи проходить безліч потоків, значна частина процесорного часу витрачається на управління самим механізмом синхронізації (очікування, повідомлення тощо). Оскільки новий API використовує апаратні конструкції рівня (атомні змінні) і чекає та блокує вільні алгоритми для впровадження безпеки потоку, набагато більше часу процесора витрачається на "виконання матеріалів", а не на управління синхронізацією.

  • вони не тільки пропонують кращу пропускну здатність, але й забезпечують більший опір проблемам життєдіяльності, таких як тупиковість та інверсія пріоритету.


34

Є дві основні причини, чому можна використовувати атомний бул. Спочатку його змінний, ви можете передати його як посилання та змінити значення, яке пов'язане, наприклад, із булевим.

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, ви повинні синхронізувати булеву змінну, яку ви використовуєте, оголосивши її мінливою або синхронізуючи навколо поля читання і запису.


4
Для любові до Бога це мало лише показати незмінність самого предмета. Я спеціально це написав для демонстраційних цілей.
Джон Вінт

І далі, якщо це було ВСЕ, що відбувалося, то так, це завжди повернеться правдою
Джон Вінт,

Це не доводить, чи це безпечно для потоків. Я можу закінчити свої фрагменти коду, щоб зробити клас дуже безпечним для потоків, але це лише вбиває мою думку.
Джон Вінт

1
Я вважаю, що тільки Летучих недостатньо. Подумайте про ситуацію, коли два потоки, які читають і записують одне і те ж значення безпосередньо з основної пам'яті, між цими потоками не відбувається жодної синхронізації - отже, можуть виникнути проблеми з одночасністю.
Шай Цадок

1
Ви маєте рацію, що не вистачить атомних установок, а потім перевіряйте операції, хоча в ОП не було достатньо контексту, щоб зробити це припущення. Скажімо, непостійних може бути недостатньо, це завжди вірно залежно від ситуації, звичайно.
Джон Вінт

18

AtomicBooleanКлас дає логічне значення , яке ви можете оновити атомарному. Використовуйте його, коли у вас є кілька потоків, що мають доступ до булевої змінної.

Огляд java.util.concurrent.atomic пакет дає вам гарне високорівневе опис того , що класи в цьому пакеті і коли використовувати їх. Я також порекомендував би книгу « Конкурс Java на практиці » Брайана Геца.


5

Витяг з опису упаковки

Пакет java.util.concurrent.atomic Опис: Невеликий набір інструментаріїв класів, які підтримують безпечне програмування без заблокування потоків на окремих змінних. [...]

Специфікації цих методів дозволяють реалізаціям використовувати ефективні атомні інструкції на рівні машин, доступні для сучасних процесорів. [...]

Примірники класів AtomicBoolean, AtomicInteger, AtomicLong та AtomicReference кожен забезпечують доступ та оновлення до однієї змінної відповідного типу. [...]

Ефекти пам’яті для доступу та оновлень атома зазвичай відповідають правилам летючих речовин:

  • get має на пам'яті ефекти читання мінливої ​​змінної.
  • Набір має ефекти на пам'ять написання (призначення) мінливої ​​змінної.
  • слабкий атомний зчитує та умовно пише змінну, впорядковується відносно інших операцій з пам'яттю на цій змінній, але в іншому випадку діє як звичайна операція з енергонезалежною пам'яттю.
  • сравнениеAndSet та всі інші операції з читання та оновлення, такі як getAndIncrement, впливають на пам'ять як читання, так і запису змінних змінних.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.