Page 260 - 6571
P. 260
внішніх методів (наприклад, з використанням оператора synch-
ronized);
4) потоки не блокуються в очікуванні звільнення монітора.
Припустимо, що у класі визначено поле done типу boole
n, значення якого встановлюється в одному потоці і зчитується в
іншому. Для синхронізації доступу до даного поля можна вико-
ристати механізм вбудованого блокування під час проектування
відповідного класу:
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; // не атомарна операція
}
Ще одним із варіантів отримати надійний доступ до спільно-
го поля з декількох потоків є використання ключового поля fin-
al. Значення поля оголошеного з модифікатором final, не мо-
же бути змінене після його ініціалізації. Фінальні поля об’єкта
ініціалізуються в його конструкторі. Якщо конструктор відпові-
дає певним простим правилам (посилання this не повинне по-
кинути конструктор до його завершення), то коректне значення
поля оголошеного з модифікатором final буде видимим для
інших потоків без синхронізації. Розглянемо наступний рядок коду:
259