Использование легковесных процессов

Данный раздел посвящен работе с потоками (в некоторых других источниках они получили название легковесные процессы). Поток – отдельная выполняемая последовательность в программе. Фактически поток – это способ реализации многозадачности в Java.

Потоки используются при решении многих задач:

  • анимация;
  • воспроизведение и обработка звуковых данных;
  • обновление и восстановление информации в фоновом режиме;
  • ожидание и обработка информации, поступающей по сети.

При запуске поток получает в свое распоряжение определенную долю ресурсов
процессора и, в дальнейшем, работает уже с ней. Говорят, что поток имеет
«тело», которое содержит операторы, оно находится в методе run().

Реализация потока

Java предусматривает две возможности реализации тела потока:

  • для класса определяется интерфейс Runnable и используется метод
    run(), а также методы start(), stop();
  • построение класса как потомка класса java.lang.Thread.

Создание потока

Метод start() выполняется каждый раз при обращении к странице,
содержащей апплет. Метод проверяет состояние объекта Thread, которая
должна быть описана выше, если значение переменной null, то создается
новый объект типа Thread и вызывается метод start() класса Thread.

Thread myNewThread;
public void start() 
{
if (myNewThread == null) 
  {
myNewThread = new Thread(this, "MyNewThreadName");
myNewThread.start();
   }
}

Рассмотрим процесс создания нового объекта Thread. Наибольший интерес для нас представляет первый аргумент в вызове конструктора Thread.
Переменная this указывает на текущий апплет. Этот аргумент должен реализовать интерфейс Runnable, после чего он становится адресатом потока.
Второй аргумент определяет имя потока.

Остановка потока

Когда вы покидаете страницу с апплетом, использующим потоки, вызывается
метод stop(), основное назначение которого является присвоение объекту
типа Thread значения null.

public void stop() {
myNewThread = null;
}

Возможен и другой вариант, а именно непосредственный вызов метода stop

myNewThread.stop();

класса Thread, но он не всегда приемлем, что связано со следующим: метод
stop может быть вызван в «неудачный» момент выполнения метода run(), в
результате чего поток может не прекратить свое выполнение. При повторном
посещении страницы будет вызван метод start и апплет начнет свое
выполнение.

Выполнение потока

Метод run() является «сердцем» потока, именно он определяет назначение не
только потока, но и, зачастую, всего класса.

public void run() {
while (Thread.currentThread() == clockThread){
repaint();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {}
}
}

Как было показано выше, перед остановкой работы апплета, значение потока
становится равным null. Метод run() будет выполняться, пока поток не
примет значение null. В данном примере апплет перерисовывает сам себя,
затем выполнение потока приостанавливается на 1 секунду (1000 милисекунд).
При вызове repaint() происходит обращение к методу paint(), который
меняет содержимое экрана.

public void paint(Graphics g) {
Date now = new Date();
g.drawString(now.getHours() + ":" + now.getMinutes() +
":" + now.getSeconds(), 5, 10);
}

Состояние потока

Новый поток

Данное выражение создает новый пустой поток:

Thread myNewThread = new Thread();

С таким потоком вы можете совершить следующие действия: запустить или
остановить (stop(), start()). Попытка вызвать любой другой метод работы
с потоком приводит к вызову исключения IllegalThreadStateException.

Выполняемый

Thread myNewThread = new Thread();
myNewThread.start();

Метод start() подготавливает все необходимые ресурсы для запуска потока
и передает управление методу run().

Невыполняемый

Поток является невыполняемым, если находится в одном из четырех
состояний:
• вызван метод sleep
• вызван метод suspend
• вызван метод wait
• поток заблокирован вводом/выводом

try {
Thread.sleep(10000);
} catch (InterruptedException e) {
}

Поток прекратил свое выполнение на 10 секунд. После непродолжительного
сна поток возобновляет свою работу. Вызов метода resume() для спящего
потока не дает результатов.
Чтобы «разбудить» спящий поток (sleep()) необходим процесс ожидания, для
возобновления работы потока (suspend()) достаточно вызвать метод
resume(). Если поток ожидает установки какой-то переменной, то прервать
это можно при помощи notify или notifyAll. Если блокировка по причине
ожидание окончания ввода/вывода, то необходимо дождаться конца обмена.

Смерть потока

Смерть наступает в двух случаях:
• после выполнения метода stop();
• по естественным причинам, т.е., когда метод run() завершил
выполнение.

Метод isAlive() возвращает true, если поток отработал метод start() и не
выполнил метод stop(). Если же возвращен false, то это либо новый поток,
либо он умер.

 

Распределение приоритета между потоками

В классе java.lang.Thread описаны три идентификатора, определяющие
приоритеты для потоков.
• MIN_PRIORITY
• NORM_PRIORITY
• MAX_PRIORITY
При создании потока ему по умолчанию устанавливается NORM_PRIORITY,
изменить приоритет можно путем использования метода setPriority(int).
Изменение приоритета потока заключается в изменении выделяемого ему
промежутка времени.

Использование нескольких потоков

Рассмотрим пример использования нескольких потоков в рамках одного
приложения.

import java.applet.Applet;
class CreatTwoThreads extends Applet {
public void CreatTwoThreads () {
new CreatThread1().start();
new CreatThread2().start();
}
}
class CreatThread1 extends Thread {
...
public void run () {
...
}
}
class CreatThread2 extends Thread {
...
public void run () {
...
}
}

Таким образом, головной класс создает два новых объекта и запускает их на
выполнение. Два вновь созданных класса являются независимыми полноправными потоками и все действия, описанные в методе run() будут
выполняться как потоковые.

 

Класс java.lang.ThreadGroup

Класс предназначен для объединения потоков в группы, что, в значительной
степени, упрощает работу с потоками и позволяет более гибко управлять их
работой. С группой потоков возможны те же основные операции, что и с
простым потоком:
• запуск;
• останов;
• установка приоритетов;
• и т.д.
К тому же для группы потоков можно определять как родителя, так и
потомков.

 

Методы класса java.lang.Thread

Условно разделим все методы на те, которые возвращают значения, и те,
которые их установливают.
Первая группа:
• activeCount() возвращает текущее число активных потоков в группе;
• currentThread() возвращает ссылку на текущий выполняющийся
поток;
• getName() возвращает имя потока;
• getPriority() возвращает приоритет потока;
• getThreadGroup() возвращает ссылку на группу, к которой
принадлежит поток;
• interrupted() возвращает, является ли поток остановленным;
• isAlive() возвращает, жив ли поток ;
• isDaemon() возвращает, является поток демоном;
• isInterrupted() возвращает, остановлен ли поток.
Вторая группа:
• setDaemon(boolean) делает поток демоном;
• setName(String) устанавливает имя потока;
• setPriority(int) изменение приоритета потока.

Похожие записи