Page 263 - 6253
P. 263
Дані методи оголошені в класі Object з модифікатором доступу final, тому вони
доступні з будь-якого об’єкту. Усі три методи можуть бути викликані тільки із
синхронізованого контексту. Хоча з точки зору своєї реалізації вони концептуально
складні, правила застосування даних методів досить прості:
1. Метод wait() призупиняє потік та виводить його із монітору до того часу,
поки будь-який інший потік не увійде у той же монітор і не викличе метод notіfy().
2. Метод notify() відновлює роботу потоку, що викликав метод wait() із того ж
самого об’єкта.
3. Метод notifyAll() відновлює роботу всіх потоків, які викликали метод wait() і
одному із потоків дається доступ до монітору.
Існують також додаткові форми методу wait(), що дозволяють вказувати час
очікування по закінченню якого потік поновлює свою роботу.
Перш ніж розглядати приклад, який демонструє міжпотокову взаємодію,
необхідно зробити одне важливе зауваження. Хоча метод wait() зазвичай перебуває
в стані очікування до того часу, поки не буде викликаний метод notify() або
notifyAll(), проте існує ймовірність, що в дуже рідкісних випадках призупинений
потік може бути поновлений підробленим сигналом. Через цю малоймовірну
можливості Oracle рекомендує виконувати виклики методу wait() всередині циклу,
що перевіряє умову очікування потоку. У наведеному нижче прикладі
продемонстровано саме такий підхід.
class Bank {
private double[] accounts;
public synchronized void transfer(int from, int to,
int amount) throws InterruptedException {
while (accounts[from] < amount)
wait(); // очікувати згідно умови
accounts[from] = accounts[from] - amount;
accounts[to] = accounts[to] + amount;
// повідомити всі потоки, що очікують згідно умови
notifyAll();
}
public synchronized double getTotalBalance() {...}
}
Метод wait() переводить потік в стан очікування, а методи notifyAll() / notify()
262