
Многопоточное программирование в Java.
Многопоточная программа может соединять несколько частей, которые работаю параллельно, каждая такая часть называется потоком или нитью, при этом каждый поток выполняется независимо от других существующих. Использование потоков позволяет писать достаточно эффективные программы, которые максимально используют ресурсы ПК, т.к время простоя сводятся к минимуму, особенно длях и сетевых средств, в которых используется язык java, т.к. время ожидания сказывается на скорости обмена информации.
Для сравнения рассмотрим однопоточную среду. Эти системы используют следующий подход: цикл обработки событий с буферизацией (в этой модели один поток управления выполняется в бесконечном цикле, накапливая в буфере одну очередь событий и решая, какое событие обрабатывает следующее. Если механизм буферизации заявит о поступлении сигнала готовности обработки события, то из цикла событий управление будет передано соответствующему обработчику. Пока обработчик не вернет управление, никакое событие в системе не обрабатывается и процессор работает в холостую т.е. в этой среде, когда поток заблокирован из-за ожидания ресурсов прекращается работа всей программы. Преимущество многопотокового программирования заключается в том, что главный цикл и механизм буферизации устранены. Один поток может перейти в состояние ожидания без остановки других потоков программы. Потоки могут находиться в следующих состояниях:
1. потоки могут выполняться
2. потоки могут быть готовыми к выполнению
3. поток может выполняться, потом быть приостановлен и затем продолжен
4. поток может быть заблокирован из-за ожидания ресурсов
5. поток может быть завершенным и после этого не может быть продолжен
К свойствам потока относит понятие «приоритета». Система java называет приоритет каждому потоку, по которому определяется его взаимодействие с другими потоками системы. Приоритет - целое число, которое определяет относительное расположение потоков по сравнению с другими. Значение приоритета само по себе смысла не имеет, может рассматриваться только по отношению к другим выполняющимся частям и скорость работы программы от приоритета не зависит. В многопоточных система, в целом, и в java в частности, приоритет используется для определения момента переключения между выполняющимися потоками, которое называется контекстным переключением.
Правила действия контекстного переключения:
1. поток может передать управление по собственной инициативе (это происходит при выходе из режима монопольного исп. процессора, при переходе в состояние ожидания или блокировке. В этом случае опрашиваются другие потоки и поток с наивысшим приоритетом, готовый к выполнению занимает время процессора.
2. поток может быть отложен потоком с более высоким приоритетом, при этом поток с низким приоритетом останавливается, поток с более высоким приоритетом может получить ресурсы процессора в любое время, когда ему это требуется (многозадачность вытеснения). Если 2 потока с равным приоритетом притендуют на ресурсы, то в java Данная ситуация решается следующим образом: потоки, претендующие на ресурсы - запускаются и каждому отводятся процессорное время на выполнение своих задач. не всегда по принципу карусели, как в винде)
Многопоточная система в Java базируется на классе Theread и интерфейся Runeble, Класс инкапсулирует методы, необходимые для выполнения потоко. При создании потока программа расширяет класс или реализует интерфейс. При запуске программы в Ява в ней есть уже поток - главный поток приложения, он важен по 2м причинам. Он способен порождать дочерние потоки, он должен быть последним потоком при завершении выполнения программы. У класса есть метод sleep (), который приводит к тому, что поток из которого он вызывается приостанавливает вывполнение на определенный период времени. Имеет 2 версии метод sleep (Long - задержка в мс), sleep (Long - задержка в мс, задержка в нс). Метод очень часто бросает исключения, которые необходимо обрабатывать вручную. Класс исключения InterutedException.
Методы класса InterutedException, которые определяют и задают параметры потока.
Setname (string) - задает имя потока
GetName () -
Данные методы применяются, если входе программы необходимо оперативное управление работой потоков и контроль за их возобновлением и остановкой
Поток создается с помощью объекта класса Treeth. При этом используются 2 метода:
1. реализация интерфейса RunEble (на практике - это саамы простой способ, при котором создается класс, который реализует интерфейс RunEble. В этом классе достаточно реализовать метод Run, в котором помещаются операторы, выполняющиеся в новом потоке. При этом метод Run может использовать другие классы и объявлять переменные. С помощью объявления метода Ran создается точка входа другого конкурирующего потока, который заканчивает свое выполнение при завершении метода Run. После создания данного класса необходимо создать экземпляр объекта Treeth внутри этого класса. Для этого применяется один из специализированных конструкторов:
Thread(Runeble, …) Данный конструктор можно применять только при использовании класса Runeble. Данный интерфейс - ссылка на экземпляр класса метод. Определяется точка входа для выполнения этого потока. Созданный поток не будет выполняться до тех пор, пока не вызван метода Start класса Thread. В свою очередь этот метод предназначен для вызова метода …
Создать поток можно с помощью стандартной конструкции
Thread t;
t = new “threeth” (this, …)
передача в качестве параметра ссылки this показывает, что необходимо передать поток, который будет вызывать метод Run данного объекта.
Расширение класса Thread. Создаем класс, расширяющий класс Theeth, после чего создается экземпляр данного класса. В расширенном классе необходимо перекрыть метод Run, который является точкой входа для данного потока. Помимо этого, в конструкторе необходимо вызвать метод Start для запуска потока. в данном случае можно использовать простейших конструктор класса Thread.
class Thred1 implements Runable {
Thread t
Thread1(){
t = new (this, «Поток»)
t.start();
}
public read run () {
2 Метод расширения класса Thread
…
Далее без изменения следует метод Run
Главный поток программы должен быть последним потоком, заканчивающим свое выполение. Если он заканчивается перед завершением последнего потока, то система Java может некорректно работать. Чтобы этого избежать используются стандартные … метод Sleep
т.е. у главного потока задержка должна быть больше, чем у дочерних, чтобы к моменту начала завершения главного потока все дочерние были завершены.
Методы, которые используются при завершении дочерних потоков
usAlive () - возвращает true, если вызванный поток выполняется
…