Методи wait і notify

Механізм блокування вирішує проблему з накладенням потоків, однак хотілося б, щоб потоки могли обмінюватися інформацією один з одним Для цього існує два методи: wait і notify Метод wait дозволяє потоку дочекатися виконання певної умови, а метод notify сповіщає всі очікують потоки про настання деякої події

визначені в класі Object і успадковуються всіма класами Вони, подібно блокуванні, відносяться до конкретних обєктів При виконанні wait ви очікуєте, що деякий потік сповістить (notify) про настання події той самий обєкт, в якому відбувається очікування

Існує стандартна конструкція, якої слід користуватися в роботі з wait і notify Потік, що очікує події, повинен включати що-небудь схоже на наступний фрагмент:

synchronized void doWhenCondition() {

while ( умова)

wait()

… Дії, що виконуються при виконанні умови ..

}

Тут слід звернути увагу на кілька аспектів:

Всі дії виконуються всередині синхронізованого методу Це

необхідно – інакше не можна бути впевненим у вмісті обєкта Наприклад, якщо метод не синхронізований, то після виконання оператора while немає гарантії, що умова виявиться істинним – ситуація могла бути змінена іншим потоком

Одне з важливих властивостей визначення wait полягає в тому, що під час призупинення потоку відбувається атомарну (atomic) зняття блокування з обєкту Коли говорять про атомарної призупинення потоку і знятті блокування, мається на увазі, що ці операції відбуваються разом і не можуть відділятися один від одного В іншому випадку знову виникла б гонка: повідомлення могло б прийти після зняття блокування, але перед призупиненням потоку У цьому випадку сповіщення ніяк не впливає на роботу потоку і фактично втрачається Коли потік відновлює роботу після отримання повідомлення, відбувається повторна блокування

Умова завжди має перевірятися всередині циклу Ніколи не слід вважати, що відновлення роботи потоку означає виконання умови Іншими словами, не замінюйте while на if

З іншого боку, метод notify викликається методами, що змінюють дані, які можуть очікуватися іншим потоком

synchronized void changeCondition() {

… Змінити величину, використовувану при перевірці умови .. notify ()

}

Кілька потоків можуть чекати один і той же обєкт Повідомлення notify відновлює той потік, який чекає довше за всіх Якщо необхідно відновити всі очікують потоки, використовуйте метод notifyAll

Наведений нижче клас реалізує концепцію черги Він містить методи, які використовуються для приміщення елементів в чергу і їх видалення:

class Queue {

/ / Перший і останній елементи черги

Element head, tail

public synchronized void append(Element p) {

if (tail == null)

head = p

else

tailnext = p

pnext = null

tail = p

notify () / / Повідомити очікують потокам про новий елементі

}

public synchronized Element get() {

try {

while(head == null)

wait () / / Очікувати появи елемента

} catch (InterruptedException e) {

return

}

Element p = head / / Запамятати перший елемент

head = headnext / / Видалити його з черги

if (head == null) / / перевірити, чи не порожня чи чергу

tail = null

return p

}

}

Така реалізація черги в чому нагадує її втілення в однопоточному системі Відмінностей не так вже й багато: методи синхронізовані при занесенні нового елемента в чергу відбувається сповіщення чекаючих потоків замість того щоб повертати null для порожньої черги, метод get чекає, поки який-небудь інший потік занесе елемент в чергу Як занесення, так і вилучення елементів черги може здійснюватися декількома потоками (а не обовязково одним)

Джерело: Арнольд К, Гослінг Д – Мова програмування Java (1997)

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*