Page 193 - 6571
P. 193
Під час роботи із змінними типу volatile не гарантується
жодна атомарність операцій. Наприклад, наведений нижче метод
не гарантує зміни значення поля done на протилежне.
public void flipDone() {
done =! done; // не атомарна операція
}
Поля та змінні типу final. Ще одним із варіантів отримати
надійний доступ до спільного поля з декількох потоків є
використання ключового поля final. Розглянемо наступний
рядок коду:
final Map accounts = new HashMap();
Змінна accounts стане доступною для інших потоків після
виконання конструктора HashMap(). Якщо не оголосити її із
модифікатором final, то немає жодної гарантії, що оновлене
значення змінної accounts виявиться доступним з інших
потоків. Якщо виконання конструктора класу HashMap буде
перервано іншим потоком, то значення змінної accounts може
виявитися рівним null. Проте, потрібно також розуміти, що
використання модифікатора final під час створення об’єкта не
робить операції над ним потокобезпечними. Якщо стан об’єкта
змінюється та зчитується в декількох потоках, то як і раніше
необхідна його синхронізація.
20.3 Атомарність операцій та потокобезпечні колекції
Спільні змінні можуть бути оголошені як volatile, тільки
за умови, що над ними не виконується жодних інших операцій,
окрім присвоєння. У пакеті java.util.concurrent.atomic
визначено цілий ряд класів, в яких ефективно використовуються
команди машинного рівня, що гарантують атомарність операцій
відмінних від присвоєння, без використання блокувань.
Наприклад, в класі AtomicInteger визначено методи
incrementAndGet() та decrementAndGet(), які здійснюють
атомарне інкрементування та декрементування цілочисельного
значення. Об’єкт даного класу можна сміливо використовувати
як спільний лічильник без додаткової синхронізації потоків.
192