Реализацию предлагаю обсуждать в комментариях
Пинг-понг
Смоделируйте игру “пинг-понг” по следующим упрощенным правилам:- играют два потока
- игра заключается в том, что один поток посылает сообщение “ Ping ”, а второй отвечает ему “Pong”.
- при этом, пока один делает “Ping”, второй ждет. Как только сообщение послано, первый поток начинает ждать, а второй отсылает “ Pong” и т.д. Фактически они поочередно блокируют друг друга.
- пусть по рандому, в методе, который делает ответ, происходит ошибка. Тогда считаем, что поток, в котором произошла ошибка - пропустил очко.
- это очко начисляем противоположному потоку.
- игра продолжается до тех, пор пока один из потоков не наберет 5 очков. Как только это произошло, игра прерывается и на консоль выводится имя победителя.
Вариант развития - волейбол, потоки сгруппированы по командам, один поток из команды подбирает мяч, производит ряд пасов, в итоге производится "Pong" на команду противника, и т.д.
АТС
Есть АТС и абоненты (потоки), которых АТС обслуживает.Абоненты могут совершать друг другу звонки, при этом, если два абонента разговаривают, то третий, при попытке дозвониться одному из них, должен получить сигнал "занято".АТС имеет ограниченную пропускную способность линий, т.е. может обслуживать одновременно не более N активных соединений между абонентами.
Далее описана реализация, которая обсуждалась на занятии. Кто-нибудь может сделать альтернативную реализацию.
Каждый абонент является потоком, который при старте подключается к АТС, и ему присваивается номер. Подключение к АТС должно происходить вызовом метода connect или register, в этом методе ссылка на вызвавший поток должна быть добавлена в список адонентов.
После регистрации абонент засыпает на рандомное время.
По истечении времени поток просыпается и выбирает случайным образом номер абонента для дозвона, количество номеров нужно запрашивать у АТС, исходя из этого количества генерировать номер для дозвона.
Поток вызывает у АТС метод call, в этом методе проверяется не занят ли принимающий абонент. Если занят возвращается сигнал "занято". (вариант для усложнения - при получении сигнала "занято", звонящий генерирует ожидание на небольшое время, и пытается дозвониться на тот же номер.)
Еще вариант для усложнения - некоторые номера могут быть не закреплены ни за одним потоком, в этом случае потоку нужно вернуть сигнал "номер не обслуживается", и абонент или прекращает дозвон и засыпает, или перегенерирует номер, и продолжает дозвон (на выбор)
Если принимающий абонент зарегистрирован и свободен, то АТС "будит" его, и предлагает принять вызов. (тут тоже можно ввести усложняющую опцию - принимающий может отсутствовать дома, или игнорировать звонящего, эта ситуация может определяться рандомно)
Если принимающий абонент принимает вызов, то звонящий генерирует время разговора, и засыпает на это время, принимающий засыпает на неопределенное время (есть такое негласное правило - первым должен ложить трубку тот кто звонит). После пробуждения, звонящий прекращает звонок (метод endCall у АТС), при этом АТС будит принимающего, и он переходит в основной режим - спячка с таймаутом, по истечении которого абонент совершает звонок.
При завершении звонка АТС вновь может направлять на обоих абонентов входящие звонки.
Упрощенные состояния абонента приведены на диаграмме:
Определение занят ли абонент можно сделать разными способами, например атс может хранить у себя состояние для каждого абонента. Или же это состояние должно храниться как поле объекта потока, и АТС должно запрашивать значение через subscriber.getState()
