Page 152 - 4868
P. 152
Ошибка! Стиль не определен. 150
Ключове слово volatile використовується для встановлення
неблокуючого режиму синхронізованого доступу до поля класу. У випадку,
коли поле класу оголошене із модифікатором volatile, то компілятор і
віртуальна машина враховують той факт, що значення поля може бути
паралельно модифіковане в іншому потоці.
Припустимо, що у класі визначено поле done типу boolean, значення
якого встановлюється в одному потоці і зчитується в іншому. Для
синхронізації доступу до даного поля можна використати механізм
вбудованого блокування під час проектування відповідного класу:
private boolean done;
public synchronized boolean isDone() { return done; }
public synchronized void setDone() { done = true; }
Проте, можливо використання вбудованого блокування є не найкращою
ідеєю. Адже методи isDone() та setDone() можуть виявитися
заблокованими, якщо інший потік заблокував об’єкт відповідного класу.
Інший варіант полягає у використанні для поля done об’єкту типу Lock.
Проте, у цьому випадку потрібно написати багато рутинного коду, тому є
зміст оголосити поле done з модифікатором volatile як це зроблено
нижче:
private volatile boolean done;
public boolean isDone() { return done; }
public void setDone() { done = true; }
Під час роботи із змінними типу volatile не гарантується жодна
атомарність операцій. Наприклад, наведений нижче метод не гарантує зміни
значення поля done на протилежне.
public void flipDone() {
done =! done; // не атомарна операція
}
Поля та змінні типу final. Ще одним із варіантів отримати надійний
доступ до спільного поля з декількох потоків є використання ключового поля
final. Розглянемо наступний рядок коду:
final Map accounts = new HashMap();
Змінна accounts стане доступною для інших потоків після виконання
конструктора HashMap(). Якщо не оголосити її із модифікатором final, то
немає жодної гарантії, що оновлене значення змінної accounts виявиться
доступним з інших потоків. Якщо виконання конструктора класу HashMap
буде перервано іншим потоком, то значення змінної accounts може
виявитися рівним null. Проте, потрібно також розуміти, що використання
модифікатора final під час створення об’єкта не робить операції над ним
потокобезпечними. Якщо стан об’єкта змінюється та зчитується в декількох
потоках, то як і раніше необхідна його синхронізація.