Java: руководство для начинающих (ЛП)
Java: руководство для начинающих (ЛП) читать книгу онлайн
"Java: руководство для начинающих"составлено Гербертом Шилдтом, автором популярных во всем мире книг по языкам программирования, таким образом, чтобы читатель смог быстро овладеть основными навыками программирования на Java. Полностью обновленное по версии Java Platform, Standard Edition 7, пятое издание этого учебного пособия начинается с рассмотрения самых основ, включая компилирование и выполнение простых программ на Java. Затем в нем описываются ключевые слова и синтаксические конструкции, составляющие основу Java как языка программирования. Далее следует изложение самых передовых языковых средств Java, включая обобщения и многопоточное программирование. И завершается книга введением в библиотеку Swing. Представленный в книге учебный и справочный материал позволяет легко и быстро научиться программировать на Java. Для облегчения процесса изучения Java книга построена следующим образом: - Основные навыки и понятия. Каждая глава начинается с перечня основных навыков и понятий, которые предстоит усвоить читателю. - Обращение к знатоку. Во врезках под этим заголовком даются полезные рекомендации в форме вопросов и ответов. - Примеры для опробования. Это примеры небольших проектов, наглядно показывающие, как применять приобретенные знания и навыки на практике. - Упражнения для самопроверки. В конце каждой главы приводятся контрольные вопросы и задания для проверки прочности усвоенного материала. - Подробные комментарии к примерам программ. Все примеры программ в этой книге снабжены подробными комментариями, описывающими демонстрируемые языковые средства и приемы программирования на Java. В этом учебном пособии для начинающих программировать на Java подробно рассмотрены все основные средства данного языка программирования: типы данных, операторы, циклы, классы, интерфейсы, методы, исключения, обобщения, пакеты, основные библиотеки классов, средства многопоточного программирования, потоки ввода-вывода, перечисления, апплеты и документирующие комментарии. Применение всех этих языковых средств Java на практике наглядно демонстрируется в небольших проектах для самостоятельного опробования. Книга снабжена массой полезных советов авторитетного автора и множеством примеров программ с подробными комментариями, благодаря которым они становятся понятными любому читателю независимо от уровня его подготовки. А для проверки прочности приобретенных знаний и навыков в конце каждой главы приводятся контрольные вопросы и задания.
Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних чтение данного контента СТРОГО ЗАПРЕЩЕНО! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту [email protected] для удаления материала
В результате выполнения этой программы на экране появляются следующие сообщения:Tick TockTick TockTick TockTick TockTick Tock`
Рассмотрим более подробно исходный код программы, имитирующей работу часов. В ее основу положен класс TickTock. В нем содержатся два метода tick () и tock (), которые взаимодействуют друг с другом. Это взаимодействие организовано таким образом, чтобы за словом "Tick” всегда следовало слово "Tock", затем слово "Tick" и т.д. Обратите внимание на переменную state. В процессе работы имитатора часов в данной переменной хранится строка "ticked" или "tocked", определяющая текущее состояГлава 1 1. Многопоточное программирование 41.1 ние часов после такта “тик” или/‘так” соответственно. В методе main () создается объект tt типа TickTock, используемый для запуска двух потоков на исполнение.
Потоки строятся на основе объектов типа MyThread. Конструктору MyThread () передаются два параметра. Первый из них задает имя потока (в данном случае — "Tick" или "Тоск"), а второй — ссылку на объект типа TickTock (в данном случае — объект tt). В методе run () из класса MyThread вызывается метод tick (), если поток называется "Tick", или же метод tock(), если поток называется "Тоск". Каждый из этих методов вызывается пять раз с параметром, принимающим логическое значение true. Работа имитатора часов продолжается до тех пор, пока методу передается параметр с логическим значением true. Последний вызов каждого из методов с параметром, принимающим логическое значение false, останавливает имитатор работы часов.
Самая важная часть программы находится в теле методов 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 TockTockTockTockTock
Это происходит потому, что методы 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, поскольку может вызывать порой серьезные осложнения в работе многопоточных программ.
