Назад
Вперед
6.3. Управление потоками
Пример демонстрирует простейшие методы
управления потоками - останов, продолжение
работы, изменение текущего приоритета.
Исходный текст примера
Архив проекта для Java WorkShop 2.0
Демонстрация
(ваш браузер должен уметь работать с аплетами
Java JDK 1.1)
Немного теории
При необходимости многопоточное приложение Java
может управлять потоками, которые оно породило.
Для этого в классе Thread имеется соответствующий
набор методов.
В этом разделе библиотеки примеров мы
продемонстрируем использование методов start, stop, а
также метода setPriority, предназначенного для
изменения приоритета потока.
Что касается методов start и stop, то вы с ними уже
встречались в предыдущих примерах этого раздела
библиотекиа примеров. Метод setPriority используется
очень просто, например:
myThread.setPriority(Thread.MIN_PRIORITY);
В качестве параметра мы передаем методу одну из
нескольких констант, определенных в классе Thread.
Возможны следующие значения:
Значение |
Приоритет |
Thread.NORM_PRIORITY |
Нормальный |
Thread.MIN_PRIORITY |
Минимальный |
Thread.MAX_PRIORITY |
Максимальный |
Описание примера
Окно аплета Rectangles, исходные тексты которого мы
опишем в этом разделе, показано на рис. 1.
Рис. 1. Окно аплета Rectangles
В этом окне мы разместили девять панелей, в
каждой из которых происходит хаотическое
рисование прямоугольников случайного цвета и
размера.
Если разместить курсор мыши над одной из
панелей, то приоритет потока, рисующего
прямоугольники в этой панели, будет понижен.
Такое понижение, однако, может быть не очень
заметно на глаз, если ваш компьютер имеет высокую
производительность.
Установив курсор в область панели и нажав любую
клавишу мыши, вы можете остановить работу
соответствующего потока. При отпускании клавиши
поток продолжит свое выполнение.
Главный класс аплета Rectangles
Главный класс нашего аплета создан на базе
класса Applet:
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
public class Rectangles extends Applet
{
. . .
}
В нем мы определили одно поле rp и несколько
методов.
Поле rp - это массив, хранящий ссылки на панели
класса RectPanel, определенного в нашем приложении:
RectPanel[] rp;
Метод init
При инициализации аплета метод init вначале
устанавливает режим размещения компонент GridLayout:
setLayout(new GridLayout(0, 3));
При этом компоненты будут расположены в
таблице из трех столбцов и произвольного
количества строк. Так как мы добавляем девять
панелей, то в результате образуются три строки.
Панели создаются и добавляются следующим
образом:
rp = new RectPanel[9];
for(int i = 0; i < 9; i++)
{
rp[i] = new RectPanel();
add(rp[i]);
}
Метод start
Когда аплет активизируется, метод start вызывает
для каждой панели метод startThread, определенный в
классе RectPanel:
public void start()
{
for(int i = 0; i < 9; i++)
rp[i].startThread();
}
В результате все девять потоков начинают свою
работу по рисованию цветных прямоугольников.
Метод stop
Если аплет становится неактивным, метод stop
останавливает все потоки, работающие в панелях:
public void stop()
{
for(int i = 0; i < 9; i++)
rp[i].stopThread();
}
Для этого вызывается метод stopThread,
определенный в классе RectPanel.
Класс RectPanel
Класс RectPanel создан на базе класса Panel:
class RectPanel extends Panel
implements Runnable, MouseListener
{
. . .
}
Дополнительно он реализует интерфейсы Runnable и MouseListener. Первый из них нужен
для организации многопоточного режима работы, а
второй - для обработки событий от мыши.
В классе RectPanel мы определили два поля:
Dimension dm;
Thread tiktak = null;
Первое из них хранит размеры панели, а второе -
ссылку на поток, выполняющий рисование
прямоугольников.
Конструктор класса RectPanel
Этот конструктор очень прост:
public RectPanel()
{
tiktak = null;
this.addMouseListener(this);
}
Он записывает в поле tiktak значение null, а затем
регистрирует обработчик событий от мыши.
Метод paint
В задачу метода paint входит определение текущих
размеров окна панели и рисование тонкой рамки
вокруг этого окна:
public void paint(Graphics g)
{
dm = getSize();
g.drawRect(
0, 0, dm.width - 1, dm.height - 1);
}
Заметим, что метод paint не рисует прямоугольники.
Это делает метод run.
Метод startThread
Когда аплет активизируется, он запускает
потоки панелей, вызывая для каждой панели метод
startThread:
public void startThread()
{
if(tiktak == null)
{
tiktak = new Thread(this);
tiktak.start();
}
}
Здесь мы просто создаем новый поток как объект
класса Thread, передавая конструктору ссылку на
объект класса RectPanel, а затем запускаем этот поток.
Метод stopThread
Метод stopThread выполняет остановку работающего
потока методом stop:
public void stopThread()
{
if(tiktak != null)
{
tiktak.stop();
tiktak = null;
}
}
Метод run
На метод run возлагается задача рисования
цветных прямоугольников в окне панели.
В теле этого метода мы определили несколько
переменных.
В переменной g хранится контекст отображения,
полученный для окна панели.
Graphics g = getGraphics();
Переменные rColor, gColor и bColor хранят текущий цвет
прямоугольника:
int rColor, gColor, bColor;
В следующих переменных хранятся координаты и
размеры текущего отображаемого прямоугольника:
int x, y, width, height;
Работа метода run выполняется в бесконечном
цикле:
while(true)
{
. . .
}
Прежде всего мы определяем, было ли уже
нарисовано окно панели. Для этого достаточно
проверить содержимое поля dm, хранящего размеры
окна панели, так как это поле инициализируется
методом paint:
if(dm != null)
{
. . .
// рисование прямоугольника
}
Прямоугольник рисуется только в том случае,
если содержимое поля dm не равно null.
Перед рисованием метод run определяет
координаты и размеры прямоугольника:
x = (int)((dm.width + 1) *
Math.random());
y = (int)((dm.height + 1) *
Math.random());
width = (int)((dm.width - 2) *
Math.random()) / 2;
height = (int)((dm.height - 2)*
Math.random()) / 2;
Далее метод run случайным образом выбирает цвет
прямоугольника и устанавливает его в контексте
отображения панели:
rColor = (int)(255 * Math.random());
gColor = (int)(255 * Math.random());
bColor = (int)(255 * Math.random());
g.setColor(
new Color(rColor, gColor, bColor));
Прямоугольник рисуется методом fillRect:
g.fillRect(x, y, width, height);
В конце каждой итерации бесконечного цикла
выполняется задержка на 10 миллисекунд:
try
{
tiktak.sleep(10);
}
catch(InterruptedException ie)
{
tiktak.stop();
}
Метод mousePressed
Когда пользователь нажимает клавишу мыши в
окне панели, управление передается методу mousePressed. Наша реализация этого
метода останавливает текущий поток, связанный с
данной панелью, методом stop:
public void mousePressed(MouseEvent e)
{
if(tiktak != null)
{
tiktak.stop();
tiktak = null;
}
}
Метод mouseReleased
Если после остановки потока возобновить его
выполнение, отжав клавишу мыши, управление будет
передано методу mouseReleased. Этот метод создаст поток
заново и запустит его на выполнение:
public void mouseReleased(MouseEvent e)
{
if(tiktak == null)
{
tiktak = new Thread(this);
tiktak.start();
}
}
Метод mouseEntered
При помещении курсора в область панели метод mouseEntered снизит приоритет потока,
связанного с данной панелью:
public void mouseEntered(MouseEvent e)
{
if(tiktak != null)
{
tiktak.setPriority(Thread.MIN_PRIORITY);
}
}
Для этого будет вызван метод setPriority с
параметром Thread.MIN_PRIORITY.
Метод mouseExited
Метод mouseExited, получающий управление при выходе
курсора за пределы окна панели, восстанавливает
нормальный приоритет потока, связанного с данной
панелью:
public void mouseExited(MouseEvent e)
{
if(tiktak != null)
{
tiktak.setPriority(Thread.NORM_PRIORITY);
}
}
Метод mouseClicked
Этот метод нами не используется, но определен
как часть интерфейса MouseListener:
public void mouseClicked(MouseEvent e)
{
}
Назад Вперед |