должны воспользоваться классом java.lang.Thread. В этом классе определены все методы, необходимые для создания потоков, управления их состоянием и синхронизации.
Как пользоваться классом Thread?
Есть две возможности.
- Во-первых, вы можете создать свой дочерний класс на базе класса Thread. При этом вы должны переопределить метод run. Ваша реализация этого метода будет работать в рамках отдельного потока.
- Во-вторых, ваш класс может реализовать интерфейс Runnable. При этом в рамках вашего класса необходимо определить метод run, который будет работать как отдельный поток.
Второй способ особенно удобен в тех случаях, когда ваш класс должен быть унаследован от какого-либо другого класса (например, от класса Applet) и при этом вам нужна многопоточность. Так как в языке программирования Java нет множественного наследования, невозможно создать класс, для которого в качестве родительского будут выступать классы Applet и Thread. В этом случае реализация интерфейса Runnable является единственным способом решения задачи.
Методы класса Thread
В классе Thread определены три поля, несколько конструкторов и большое количество методов, предназначенных для работы с потоками. Ниже мы привели краткое описание полей, конструкторов и методов.
С помощью конструкторов вы можете создавать потоки различными способами, указывая при необходимости для них имя и группу. Имя предназначено для идентификации потока и является необязательным атрибутом. Что же касается групп, то они предназначены для организации защиты потоков друг от друга в рамках одного приложения.
Методы класса Thread предоставляют все необходимые возможности для управления потоками, в том числе для их синхронизации.
Поля
Три статических поля предназначены для назначения приоритетов потокам.
- NORM_PRIORITY
Нормальный
public final static int NORM_PRIORITY;
- MAX_PRIORITY
Максимальный
public final static int MAX_PRIORITY;
- MIN_PRIORITY
Минимальный
public final static int MIN_PRIORITY;
Конструкторы
Создание нового объекта Thread
public Thread();
Создвание нового объекта Thread с указанием объекта, для которого будет вызываться метод run
public Thread(Runnable target);
Аналогично предыдущему, но дополнительно задается имя нового объекта Thread
public Thread(Runnable target, String name);
Создание объекта Thread с указанием его имени
public Thread(String name);
Создание нового объекта Thread с указанием группы потока и объекта, для которого вызывается метод run
public Thread(ThreadGroup group,
Runnable target);
Аналогично предыдущему, но дополнительно задается имя нового объекта Thread
public Thread(ThreadGroup group,
Runnable target, String name);
Создание нового объекта Thread с указанием группы потока и имени объекта
public Thread(ThreadGroup group, String name);
Методы
- activeCount
Текущее количество активных потоков в группе, к которой принадлежит поток
public static int activeCount();
- checkAccess
Текущему потоку разрешается изменять объект Thread
public void checkAccesss();
- countStackFrames
Определение количества фреймов в стеке
public int countStackFrames();
- currentThread
Определение текущего работающего потока
public static Thread currentThread();
- destroy
Принудительное завершение работы потока
public void destroy();
- dumpStack
Вывод текущего содержимого стека для отладки
public static void dumpStack();
- enumerate
Получение всех объектов Tread данной группы
public static int enumerate(Thread tarray[]);
- getName
Определение имени потока
public final String getName();
- getPriority
Определение текущего приоритета потока
public final int getPriority();
- getThreadGroup
Определение группы, к которой принадлежит поток
public final ThreadGroup getThreadGroup();
- interrupt
Прерывание потока
public void interrupt();
- interrupted
Определение, является ли поток прерванным
public static boolean interrupted();
- isAlive
Определение, выполняется поток или нет
public final boolean isAlive();
- isDaemon
Определение, является ли поток демоном
public final boolean isDaemon();
- isInterrupted
Определение, является ли поток прерванным
public boolean isInterrupted();
- join
Ожидание завершения потока
public final void join();
Ожидание завершения потока в течение заданного времени. Время задается в миллисекундах
public final void join(long millis);
Ожидание завершения потока в течение заданного времени. Время задается в миллисекундах и наносекундах
public final void join(long millis, int nanos);
- resume
Запуск временно приостановленного потока
public final void resume();
- run
Метод вызывается в том случае, если поток был создан как объект с интерфейсом Runnable
public void run();
- setDaemon
Установка для потока режима демона
public final void setDaemon(boolean on);
- setName
Устаовка имени потока
public final void setName(String name);
- setPriority
Установка приоритета потока
public final void setPriority(int newPriority);
- sleep
Задержка потока на заднное время. Время задается в миллисекундах и наносекундах
public static void sleep(long millis);
Задержка потока на заднное время. Время задается в миллисекундах и наносекундах
public static void sleep(long millis, int nanos);
- start
Запуск потока на выполнение
public void start();
- stop
Остановка выполнения потока
public final void stop();
Аварийная остановка выполнения потока с заданным исключением
public final void stop(Throwable obj);
- suspend
Приостановка потока
public final void suspend();
- toString
Строка, представляющая объект-поток
public String toString();
- yield
Приостановка текущего потока для того чтобы управление было передано другому потоку
public static void yield ();
Создание дочернего класса на базе класса Thread
Рассмотрим первый способ реализации многопоточности, основанный на наследовании от класса Thread. При использовании этого способа вы определяете для потока отдельный класс, например, так:
class DrawRectangles extends Thread
{
. . .
public void run()
{
. . .
}
}
Здесь определен класс DrawRectangles, который является дочерним по отношению к классу Thread.
Обратите внимание на метод run. Создавая свой класс на базе класса Thread, вы должны всегда определять этот метод, который и будет выполняться в рамках отдельного потока.
Заметим, что метод run не вызывается напрямую никакими другими методами. Он получает управление при запуске потока методом start.
Как это происходит?
Рассмотрим процедуру запуска потока на примере некоторого класса DrawRectangles.
Вначале ваше приложение должно создать объект класса Thread:
public class MultiTask2 extends Applet
{
Thread m_DrawRectThread = null;
. . .
public void start()
{
if (m_DrawRectThread == null)
{
m_DrawRectThread = new DrawRectangles(this);
m_DrawRectThread.start();
}
}
}
Создание объекта выполняется оператором new в методе start, который получает управление, когда пользователь открывает документ HTML с аплетом. Сразу после создания поток запускается на выполнение, для чего вызывается метод start.
Что касается метода run, то если поток используется для выполнения какой либо периодической работы, то этот метод содержит внутри себя бесконечный цикл. Когда цикл завершается и метод run возвращает управление, поток прекращает свою работу нормальным, не аварийным образом. Для аварийного завершения потока можно использовать метод interrupt.
Остановка работающего потока выполняется методом stop. Обычно остановка всех работающих потоков, созданных аплетом, выполняется методом stop класса аплета:
public void stop()
{
if (m_DrawRectThread != null)
{
m_DrawRectThread.stop();
m_DrawRectThread = null;
}
}
Напомним, что этот метод вызывается, когда пользователь покидает страницу сервера Web, содержащую аплет.
Реализация интерфейса Runnable
Описанный выше способ создания потоков как объектов класса Thread или унаследованных от него классов кажется достаточнао естественным. Однако этот способ не единственный. Если вам нужно создать только один поток, работающую одновременно с кодом аплета, проще выбрать второй способ с использованием интерфейса Runnable.
Идея заключается в том, что основной класс аплета, который является дочерним по отношению к классу Applet, дополнительно реализует интерфейс Runnable, как это показано ниже:
public class MultiTask extends
Applet implements Runnable
{
Thread m_MultiTask = null;
. . .
public void run()
{
. . .
}
public void start()
{
if (m_MultiTask == null)
{
m_MultiTask = new Thread(this);
m_MultiTask.start();
}
}
public void stop()
{
if (m_MultiTask != null)
{
m_MultiTask.stop();
m_MultiTask = null;
}
}
}
Внутри класса необходимо определить метод run, который будет выполняться в рамках отдельного потока. При этом можно считать, что код аплета и код метода run работают одновременно как разные потоки.
Для создания потока используется оператор new. Поток создается как объект класса Thread, причем конструктору передается ссылка на класс аплета:
m_MultiTask = new Thread(this);
При этом, когда поток запустится, управление получит метод run, определенный в классе аплета.
Как запустить поток?
Запуск выполняется, как и раньше, методом start. Обычно поток запускается из метода start аплета, когда пользователь отображает страницу сервера Web, содержащую аплет. Остановка потока выполняется методом stop.