Page 145 - 4868
P. 145
143 Ошибка! Стиль не определен.
Проте, що робити, якщо на рахунку немає достатньої кількості коштів?
Єдине рішення – це очікувати до того часу, поки рахунок не буде поповнено
під час виконання іншого потоку. Проте, у представленому прикладі потік
володіє монопольним доступом до об’єкта bankLock, тому жоден інший
потік не в змозі виконати поповнення рахунку. Тому єдиним правильним
рішенням є використання умовного об’єкту.
З будь-яким об’єктом блокування може бути пов’язаний один або
декілька умовних об’єктів, які створюються за допомогою фабричного
методу newCondition(). Кожному умовному об’єкту можна присвоїти ім’я,
що буде асоціюватися з умовою, яку він представляє. Наприклад, об’єкт, що
представляє умову «достатньо коштів», визначається наступним чином:
class Bank {
private Condition sufficientFunds;
...
public Bank() {
...
sufficientFunds = bankLock.newCondition();
}
}
Фабричний метод newCondition() повертає умовний об’єкт,
пов’язаний з відповідним блокуванням. Якщо під час виконання методу
transfer() буде виявлено, що коштів на рахунку недостатньо, то він
виконає виклик методу await(), який переводить поточний потік в режим
очікування, що дає змогу поповнити рахунок в іншому потоці:
sufficientFunds.await();
Існує істотна відмінність між потоком, що очікує можливості захопити
блокування, і потоком, що викликав метод await(). Виклик методу
await() переводить потік в режим очікування, визначений для даної умови.
Потік залишається в режимі очікування доти, поки інший потік не викличе
метод signalAll() по тій же умові очікування.
Коли сума коштів на рахунку стане більшою amount, то потік в якому
було виконано переказ коштів повинен викликати наступний код:
sufficientFunds.signalAll();
При цьому, планувальник потоків переводить усі потоки, що
задовольняють умові очікування в активний стан, і як тільки об’єкт
блокування стане доступним, один з цих потоків захопить його і продовжить
своє виконання з того місця, де він був призупинений, отримавши керування
після виклику методу await().
У даний момент потік знову повинен перевірити умову очікування,
проте немає жодних гарантій, що вона тепер буде виконаною. Адже метод
signalAll() просто сигналізує призупиненим потокам про те, що умова
тепер може бути задоволеною і, що її варто перевірити заново.
Також важливо, щоб метод signalAll() був викликаний в будь-якому