Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: Общие вопросы > Идеология методов wait, notify, notifyAll.


Автор: Bakuard 1.10.2017, 12:50
Доброго времени суток.

Возникло несколько вопросов связанных с поведением методов wait, notify, notifyAll. Сразу хочу уточнить - я понимаю как работают эти методы, но не понимаю, почему разработчики языка решили реализовать именно такое поведение. 
А именно: Почему для вызовов этих методов необходимо владеть монитором объекта? Почему эти методы реализованы в классе Object?
Помогите пожалуйста разобраться.

Автор: rfq 15.12.2017, 02:11
Параллельное программирование - это очень просто, запускай себе потоки и процессы, делов-то. Сложности начинаются, когда параллельные процессы должны взаимодействовать. Рассмотрим простейший пример:

- поток А записывает значение в переменную П
- поток Б читает это значение

Поскольку про относительную скорость потоков нам ничего не известно, то как избежать ситуации, когда Б будет читать еще не записанное значение?

Решение в том, чтобы для обмена данными использовать не простые переменные, а контейнеры токенов. Токен (token) - это фишка в настольной игре. Его можно разместить на клетке игрового поля, можно передвинуть, при этом из прежней клетки он исчезает. Фишки казино - тоже токены, они перемещаются от дилера к игроку и обратно. Конкретно в нашем случае, поток А кладет токен в контейнер К, а поток Б пытается его извлечь. При этом если токена там еще нет, поток засыпает до момента его появления. Операция размещения токенов будит ждущие потоки, если они есть.

Собственно, токен - это обычное значение, примитивного или ссылочного типа, токеном его делает контейнер, в котором он размещается. Контейнер - это объект, обеспечивающий надежную реализацию операций размещения и извлечения токенов  в многопоточной среде.

Итак, для организации контейнера токенов нам надо 3 вещи:
- блокировка контейнера на время операции - как правило, нам нужно несколько действий, чтобы разместить или извлечь токен, важно, чтобы никто во время операции не вклинивался, не только с записью, но и с чтением
- операция перехода потока в состояние ожидания события изменения состояния контейнера (поток может ждать не только размещения токена, но и освобождения места, чтобы положить свой токен)
- операция оповещения ждущих потоков о том, что состояние контейнера изменилось.

Вы, конечно, узнали операции synchronized, wait и notify.

Ну а почему эти операции разработчики языка решили сделать применимыми к любому объекту - просто поняли, что так сделать можно и решили не ограничивать свободу программиста, чтобы он мог сделать контейнер на базе любого существующего класса.

Вот только я считаю, что начинать изучение параллельного программирования с написания контейнеров токенов (иными словами, с использования вышеупомянутых операций) - это неправильно. Это ответственное дело, полное подводных камней, требующее высокой квалификации. Существуют готовые реализации контейнеров, например, реализации интерфейса BlockingQueue, которые закроют ваши потребности на 90%, еще несколько процентов закроет класс Semaphore - контейнер для неразличимых токенов. Свои контейнеры нужны, если у вас возникли специфические задачи, а вы уже перепробовали все стандартные реализации и остались неудовлетворенными. И конечно, прежде чем начать писать свое, нужно изучить коды стандартных реализаций.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)