Вход/Регистрация
Java: руководство для начинающих
вернуться

Шилдт Герберт

Шрифт:

Самая важная часть программы находится в теле методов tick и tock из класса TickTock. Начнем с метода tick . Для удобства анализа ниже представлен исходный код этого метода. synchronized void tick(boolean running) { if(!running) { // остановить часы state = "ticked"; notifyO; // уведомить ожидающие потоки return; } System.out.print("Tick "); state = "ticked"; // установить текущее состояние после такта "тик" notify; // уведомить метод tock о возможности продолжить выполнение try { while(!state.equals("tocked") ) wait; // ожидать завершения метода tock } catch(InterruptedException exc) { System.out.println("Thread interrupted."); } }

Прежде всего обратите внимание на то, что в объявлении метода tick присутствует ключевое слово synchronized, указываемое в качестве модификатора доступа. Как пояснялось ранее, действие методов wait и notify распространяется только на синхронизированные методы. В начале метода tick проверяется значение параметра running. Этот параметр служит для корректного завершения программы, имитирующей работу часов. Если он принимает логическое значение false, имитатор работы часов должен быть остановлен. Если же параметр running принимает логическое значение true, а переменная state — значение "ticked", вызывается метод notify , разрешающий ожидающему потоку возобновить свое исполнение. Мы еще вернемся к этому вопросу несколько ниже.

По ходу работы имитируемых часов в методе tick выводится слово "Tick", переменная state принимает значение "ticked", а затем вызывается метод notify . Вызов метода notify возобновляет исполнение ожидающего потока. Далее в цикле while вызывается метод wait . В итоге выполнение метода tick будет приостановлено до тех пор, пока другой поток не вызовет метод notify . Таким образом, очередной шаг цикла не будет выполнен до тех пор, пока другой поток не вызовет метод notify для того же самого объекта. Поэтому когда вызывается метод tick , на экран выводится слово "Tick" и другой поток получает возможность продолжить свое исполнение, а затем выполнение этого метода приостанавливается.

В том цикле while, в котором вызывается метод wait , проверяется значение переменной state. Значение "tocked", означающее завершение цикла, будет установлено только после выполнения метода tock . Этот цикл предотвращает продолжение исполнения потока в результате ложной активизации. Если по окончании ожидания в переменной state не будет присутствовать значение "tocked", значит, имела место ложная активизация, и метод wait будет вызван снова.

Метод tock является почти точной копией метода tick . Его отличие состоит лишь в том, что он выводит на экран слово "Tock" и присваивает переменной state значение "tocked". Следовательно, когда метод tock вызывается, он выводит на экран слово "Tock", вызывает метод notify , а затем переходит в состояние ожидания. Если проанализировать работу сразу двух потоков, то станет ясно, что за вызовом метода tick тотчас следует вызов метода tock , после чего снова вызывается метод tick , и т.д. В итоге оба метода синхронизируют друг друга.

При остановке имитатора работы часов вызывается метод not if у . Это нужно для того, чтобы возобновить исполнение ждущего потока. Как упоминалось выше, в обоих методах, tick и tock , после вывода сообщения на экран вызывается метод wait . В результате при остановке имитатора работы часов один из потоков обязательно будет находиться в состоянии ожидания. Следовательно, последний вызов метода notify необходим. В качестве эксперимента попробуйте удалить вызов метода notify и посмотрите, что при этом произойдет. Вы увидите, что программа зависнет, и вам придется завершить ее нажатием комбинации клавиш . Дело в том, что когда метод tock в последний раз получает управление, он вызывает метод wait , после чего не происходит вызов метода not if у , позволяющего завершиться методу tock . В итоге метод tock остается в состоянии бесконечного ожидания.

Если у вас еще остаются сомнения по поводу того, что методы wait и notify необходимы для организации нормального выполнения программы, имитирующей работу часов, замените в ее исходном коде класс TickTock приведенным ниже его вариантом. Он отличается тем, что в нем удалены вызовы методов wait и notify . // В этой версии вызовы методов wait и notify отсутствуют, class TickTock { String state; // содержит сведения о состоянии часов synchronized void tick(boolean running) { if(!running) { // остановить часы state = "ticked"; return; } System.out.print("Tick "); state = "ticked"; // установить текущее состояние после такта "тик" } synchronized void tock(boolean running) { if(!running) { // остановить часы state = "tocked"; return; } System.out.println("Tock") ; state = "tocked"; // установить текущее состояние после такта "так" } }

Теперь программа выводит на экран следующие сообщения: Tick Tick Tick Tick Tick Tock Tock Tock Tock Tock

Это происходит потому, что методы tick и tock не взаимодействуют друг с другом. Приостановка, возобновление и остановка потоков

Иногда оказывается полезно приостановить или даже полностью прекратить исполнение потока. Допустим, отдельный поток используется для отображения времени. Если пользователю не нужны часы на экране, то отображающий их поток можно приостановить. Независимо от причин, по которым требуется временная остановка потока, сделать это нетрудно, как, впрочем, и возобновить исполнение потока.

Механизмы приостановки, возобновление и остановки потоков менялись в разных версиях Java. До появления версии Java 2 для этих целей применялись методы suspend , resume и stop , определенные в классе Thread. Ниже приведены общие формы их объявления. final void resume final void suspend final void stop

На первый взгляд кажется, что упомянутые выше методы удобны для управления потоками, но пользоваться ими все же не рекомендуется по следующим причинам. При выполнении метода suspend иногда возникают серьезные осложнения, приводящие к взаимоблокировке. Метод resume сам по себе безопасен, но применяется только в сочетании с методом suspend . Что же касается метода stop из класса Thread, то и он не рекомендуется к применению, начиная с версии Java 2, поскольку может вызывать порой серьезные осложнения в работе многопоточных программ.

  • Читать дальше
  • 1
  • ...
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: