Page 69 - 4657
P. 69
використаний виклик sleep. У реальних же ситуаціях цей стан,
як правило, важко визначити, оскільки незрозуміло, де саме
відбувається переключення контексту, і цей ефект менш
помітний і не завжди відтворюються від запуску до запуску
програми. Так що якщо у вас є метод (чи ціла група методів), що
маніпулює внутрішнім станом об'єкта, використовуваного в
програмі з рівнобіжними підпроцесами, щоб уникнути стану
гонки вам належить використовувати в його заголовку ключове
слово synchronized.
Взаємодія підпроцесів
У Java мається елегантний механізм спілкування між
підпроцесами, заснований на методах wait, notify і notifyAll. Ці
методи реалізовані, як final-методи класу Object, так що вони є в
будь-якому Java-класі. Усі ці методи повинні викликатися тільки
із синхронізованих методів. Правила використання цих методів
дуже прості:
- wait - приводить до того, що поточний підпроцес віддає
керування і переходить у режим чекання - доти поки інший
під-процес не викликає метод notify з тим же об'єктом;
- notify - виводить зі стану чекання перший з підпроцесів,
що викликали wait з даним об'єктом;
- notifyAll - виводить зі стану чекання всі підпроцеси, що
викликали wait з даним об'єктом.
Нижче приведений приклад програми з наївною реалізацією
проблеми постачальник-споживач. Ця програма складається з
чотирьох простих класів: класу Q, що представляє собою нашу
реалізацію черги, доступ до якої ми намагаємося
синхронізувати; постачальника (клас Producer), що виконується
в окремому підпроцесі і поміщає дані в чергу; споживача (клас
Consumer), що теж представляє собою підпроцес і витянуті дані
з черги; і, нарешті, крихітного класу PC, що створює по одному
об'єкті кожного з перерахованих класів.
class Q {
int n;
67