Kniga-Online.club

Н.А. Вязовик - Программирование на Java

Читать бесплатно Н.А. Вязовик - Программирование на Java. Жанр: Программирование издательство неизвестно, год 2004. Так же читаем полные версии (весь текст) онлайн без регистрации и SMS на сайте kniga-online.club или прочесть краткое содержание, предисловие (аннотацию), описание и ознакомиться с отзывами (комментариями) о произведении.
Перейти на страницу:

Опасность возникновения взаимных блокировок заставляет с особенным вниманием относиться к работе с потоками. Например, важно помнить, что если у объекта потока был вызван метод sleep(..), то такой поток будет бездействовать определенное время, но при этом все заблокированные им объекты будут оставаться недоступными для блокировок со стороны других потоков, а это потенциальный deadlock. Такие ситуации крайне сложно выявить путем тестирования и отладки, поэтому вопросам синхронизации надо уделять много времени на этапе проектирования.

Методы wait(), notify(), notifyAll() класса Object

Наконец, перейдем к рассмотрению трех методов класса Object, завершая описание механизмов поддержки многопоточности в Java.

Каждый объект в Java имеет не только блокировку для synchronized блоков и методов, но и так называемый wait-set, набор потоков исполнения. Любой поток может вызвать метод wait() любого объекта и таким образом попасть в его wait-set. При этом выполнение такого потока приостанавливается до тех пор, пока другой поток не вызовет у этого же объекта метод notifyAll(), который пробуждает все потоки из wait-set. Метод notify() пробуждает один случайно выбранный поток из данного набора.

Однако применение этих методов связано с одним важным ограничением. Любой из них может быть вызван потоком у объекта только после установления блокировки на этот объект. То есть либо внутри synchronized -блока с ссылкой на этот объект в качестве аргумента, либо обращения к методам должны быть в синхронизированных методах класса самого объекта. Рассмотрим пример:

public class WaitThread implements Runnable {

private Object shared;

public WaitThread(Object o) {

shared=o;

}

public void run() {

synchronized (shared) {

try {

shared.wait();

}

catch (InterruptedException e) {

}

System.out.println("after wait");

}

}

public static void main(String s[]) {

Object o = new Object();

WaitThread w = new WaitThread(o);

new Thread(w).start();

try {

Thread.sleep(100);

}

catch (InterruptedException e) {

}

System.out.println("before notify");

synchronized (o) {

o.notifyAll();

}

}

}

Результатом программы будет:

before notify

after wait

Обратите внимание, что метод wait(), как и sleep(), требует обработки InterruptedException, то есть его выполнение также можно прервать методом interrupt().

В заключение рассмотрим более сложный пример для трех потоков:

public class ThreadTest implements Runnable {

final static private Object shared=new Object();

private int type;

public ThreadTest(int i) {

type=i;

}

public void run() {

if (type==1 || type==2) {

synchronized (shared) {

try {

shared.wait();

}

catch (InterruptedException e) {

}

System.out.println("Thread "+type+" after wait()");

}

}

else {

synchronized (shared) {

shared.notifyAll();

System.out.println("Thread "+type+" after notifyAll()");

}

}

}

public static void main(String s[]) {

ThreadTest w1 = new ThreadTest(1);

new Thread(w1).start();

try {

Thread.sleep(100);

}

catch (InterruptedException e) {

}

ThreadTest w2 = new ThreadTest(2);

new Thread(w2).start();

try {

Thread.sleep(100);

}

catch (InterruptedException e) {

}

ThreadTest w3 = new ThreadTest(3);

new Thread(w3).start();

}

}

Пример 12.5.

Результатом работы программы будет:

Thread 3 after notifyAll()

Thread 1 after wait()

Thread 2 after wait()

Пример 12.6.

Рассмотрим, что произошло. Во-первых, был запущен поток 1, который тут же вызвал метод wait() и приостановил свое выполнение. Затем то же самое произошло с потоком 2. Далее начинает выполняться поток 3.

Сразу обращает на себя внимание следующий факт. Еще поток 1 вошел в synchronized -блок, а стало быть, установил блокировку на объект shared. Но, судя по результатам, это не помешало и потоку 2 зайти в synchronized -блок, а затем и потоку 3. Причем, для последнего это просто необходимо, иначе как можно "разбудить" потоки 1 и 2?

Можно сделать вывод, что потоки, прежде чем приостановить выполнение после вызова метода wait(), отпускают все занятые блокировки. Итак, вызывается метод notifyAll(). Как уже было сказано, все потоки из wait-set возобновляют свою работу. Однако чтобы корректно продолжить исполнение, необходимо вернуть блокировку на объект, ведь следующая команда также находится внутри synchronized -блока!

Получается, что даже после вызова notifyAll() все потоки не могут сразу возобновить работу. Лишь один из них сможет вернуть себе блокировку и продолжить работу. Когда он покинет свой synchronized -блок и отпустит объект, второй поток возобновит свою работу, и так далее. Если по какой-то причине объект так и не будет освобожден, поток так никогда и не выйдет из метода wait(), даже если будет вызван метод notifyAll(). В рассмотренном примере потоки один за другим смогли возобновить свою работу.

Кроме того, определен метод wait() с параметром, который задает период тайм-аута, по истечении которого поток сам попытается возобновить свою работу. Но начать ему придется все равно с повторного получения блокировки.

Заключение

В этой лекции были рассмотрены принципы построения многопоточного приложения. В начале разбирались достоинства и недостатки такой архитектуры – как правило ОС не выделяет отдельный процессор под каждый процесс, а значит применяется процедура time slicing. Было выделено три признака, указывающие на целесообразность запуска нескольких потоков в рамках программы.

Основу работы с потоками в Java составляют интерфейс Runnable и класс Thread. С их помощью можно запускать и останавливать потоки, менять их свойства, среди которых основные: приоритет и свойство daemon. Главная проблема, возникающая в таких программах - одновременный доступ нескольких потоков к одним и тем же данным, в первую очередь -– к полям объектов. Для понимания, как в Java решается эта задача, был сделан краткий обзор по организации памяти в JVM, работы с переменными и блокировками. Блокировки, несмотря на название, сами по себе не ограничивают доступ к переменной. Программист использует их через ключевое слово synchronized, которое может быть указано в сигнатуре метода или в начале блока. В результате выполнение не будет продолжено, пока блокировка не освободится.

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

В завершение рассматривались специализированные методы базового класса Object, которые также позволяют управлять последовательностью работы потоков.

13. Лекция: Пакет java.lang

В этой лекции рассматривается основная библиотека Java – java.lang. В ней содержатся классы Object и Class, классы-обертки для примитивных типов, класс Math, классы для работы со строками String и StringBuffer, системные классы System, Runtime и другие. В этом же пакете находятся типы, уже рассматривавшиеся ранее,– для работы с исключительными ситуациями и потоками исполнения.

Введение

В состав пакета java.lang входят классы, составляющие основу для всех других, и поэтому он является наиболее важным из всех, входящих в Java API. Поскольку без него не может обойтись ни один класс, каждый модуль компиляции содержит неявное импортирование этого пакета ( import java.lang.*; ).

Перечислим классы, составляющие основу пакета.

Object – является корневым в иерархии классов.

Class – экземпляры этого класса являются описаниями объектных типов в памяти JVM.

String – представляет собой символьную строку, содержит средства работы с нею.

StringBuffer – используется для работы (создания) строк.

Number – абстрактный класс, являющийся суперклассом для классов-объектных оберток числовых примитивных типов Java.

Character – объектная обертка для типа char.

Boolean – объектная обертка для типа boolean.

Math – реализует набор базовых математических функций.

Throwable – базовый класс для объектов, представляющих исключения. Любое исключение, которое может быть брошено и, соответственно, перехвачено блоком catch, должно быть унаследовано от Throwable.

Thread – позволяет запускать и работать с потоками выполнения в Java. Runnable – может использоваться в сочетании с классом Thread для описания потоков выполнения.

ThreadGroup – позволяет объединять потоки в группу и производить действия сразу над всеми потоками в ней. Существуют ограничения по безопасности на манипуляции с потоками из других групп.

System – содержит полезные поля и методы для работы системного уровня.

Runtime – позволяет приложению взаимодействовать с окружением, в котором оно запущено.

Process – представляет интерфейс к внешней программе, запущенной при помощи Runtime.

ClassLoader – отвечает за загрузку описания классов в память JVM.

SecurityManager – для обеспечения безопасности накладывает ограничения на данную среду выполнения программ.

Compiler – используется для поддержки Just-in-Time компиляторов.

Интерфейсы:

Cloneable – должен быть реализован объектами, которые планируется клонировать с помощью средств JVM;

Comparable – позволяет упорядочивать (сортировать, сравнивать) объекты каждого класса, реализующего этот интерфейс.

Перейти на страницу:

Н.А. Вязовик читать все книги автора по порядку

Н.А. Вязовик - все книги автора в одном месте читать по порядку полные версии на сайте онлайн библиотеки kniga-online.club.


Программирование на Java отзывы

Отзывы читателей о книге Программирование на Java, автор: Н.А. Вязовик. Читайте комментарии и мнения людей о произведении.


Уважаемые читатели и просто посетители нашей библиотеки! Просим Вас придерживаться определенных правил при комментировании литературных произведений.

  • 1. Просьба отказаться от дискриминационных высказываний. Мы защищаем право наших читателей свободно выражать свою точку зрения. Вместе с тем мы не терпим агрессии. На сайте запрещено оставлять комментарий, который содержит унизительные высказывания или призывы к насилию по отношению к отдельным лицам или группам людей на основании их расы, этнического происхождения, вероисповедания, недееспособности, пола, возраста, статуса ветерана, касты или сексуальной ориентации.
  • 2. Просьба отказаться от оскорблений, угроз и запугиваний.
  • 3. Просьба отказаться от нецензурной лексики.
  • 4. Просьба вести себя максимально корректно как по отношению к авторам, так и по отношению к другим читателям и их комментариям.

Надеемся на Ваше понимание и благоразумие. С уважением, администратор kniga-online.


Прокомментировать
Подтвердите что вы не робот:*
Подтвердите что вы не робот:*