Потоки в Java

Цель занятия

Познакомиться с классом потоков Thread и возможностями его использования для реализации динамических функций приложения (апплета). Изучить использование главного метода потока run (), а также применение интерфейса Runnabie. Подробное описание потоков изложено в [15].

Краткие теоретические сведения

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

class mythread extends Thread {

int sum, i;

public void run()

while(true)

{

if (Math.random()>0.4)

{i=l;} else {i=-l;} try

{sleep(100);} catch(Exception err)

{System.out.println(""+err) ; }

Account.putmoney((int) (i*Math.random()*100));

}

}

}

Класс потока должен расширять базовый класс Thread. В примере класс потока назван mythread. Запомните, что у потока главным методом является run (). Как только этот метод выполнится, поток будет уничтожен. Поэтому при программировании потока следует записать свой собственный код для run (). В приведенном примере метод run () запрограммирован так, что он выполняется в бесконечном цикле while (true) {…}• На каждой очередной итерации цикла поток вызывает метод из другого класса: Account.putmoney(), который и моделирует занесение денег или их изъятие со счета в сумме, определяемой как i*Math.random()*100). Заметим, что если i==i, то деньги добавляются к счету; если i==-i, то деньги изымаются со счета. Наконец, отмечаем, что команда sieep(i00) приостанавливает работу потока на 100 миллисекунд (1 милисекунда = 0.001 с). Поэтому очередная банковская операция клиента происходит с задержкой на это время. Некоторые команды могут повлечь за собой возникновение системных ошибок. Java требует такие команды охранять. Охрана состоит в применении конструкции try-catch. То, что записывается в фигурных скобках после try, — есть охраняемая последовательность команд. То, что записывается в фигурных скобках после catch, — есть последовательность действий, выполняемая в случае возникновения системной ошибки. В нашем примере это выдача сообщения об ошибке на системную консоль:

System.out.println(""+err);.

Теперь обратимся к классу Account. Он определен следующим образом.

class Account {

static int balance=10000;

static public void putmoney(int amount)

{

balance=balance+amount;

}

}

Этот класс имеет следующее назначение: в нем находится статическая переменная baiance, содержащая текущий счет, а также метод для моделирования операций со счетом:

static public void putmoney(int amount)

{balance=balance+amount;}

Суть этого метода проста: он получает на входе сумму amount и добавляет ее к балансу baiance. Итак, запомним, что метод Account. putmoney () вызывается из потока, имитирующего клиента, а не реализуется в самом потоке.

Остается отметить назначение самого апплета. На рис. 2.14 представлено его окно после запуска.

На апплете размещена кнопка, при нажатии которой отображается текущее состояние счета клиента.

Событие от программной кнопки запрограммировано так:

public void actionPerformed(ActionEvent a_e)

{

summa=Account.balance; repaint();

}

Переменной summa присваивается текущее значение переменной baiance класса Account. Одновременно обратите внимание на то, как выполняется обращение к этой переменной. Завершающая команда repaint () обязательна для перерисовки окна апплета. Команда repaint () запускает метод paint () .

Рис. 2.14. Окно апплета с данными банковского счета

Метод paint о выполняет отображение суммы в окне апплета:

public void paint(Graphics g)

setBackground(Color.pink) ; g.setColor(Color.white);

g.drawString("Your Account is:"+summa,100,100);}

Обратите внимание на то, что аргумент "Your Account is: "+summa есть строка, хотя он получается путем присоединения к строке целого числа, представленного переменной summa.

Наконец, приведем текст инициализации окна апплета:

public class myapplet extends Applet implements ActionListener

mythread myth=new mythread(); int summa=0;

Button btn=new Button("Press to know Account");

public void init()

setLayout(null) ; add(btn);

btn.setBounds(100,200,120, 20); btn.addActionListener(this) ; myth.start() ;

Здесь следует обратить внимание на следующее. Объявление потока производится так:

mythread myth=new mythread();

Здесь mythread — это имя класса потока (определено ранее). Переменная myth — это имя потока. Запуск потока на выполнение параллельно с основной программой реализуется в строке:

myth.start();

Теперь объединим все рассмотренные секции в единое приложение (листинг 2.18).

Листинг 2.18. Работа с потоком

import java.awt.*; import java.applet.*; import java.awt.event.*;

public class myapplet extends Applet implements ActionListener

mythread myth=new mythread(); int summa=0;

Button btn=new Button("Press to know Account");

public void init()

setLayout(null); add(btn);

btn.setBounds(100,200,120, 20); btn.addActionListener(this) ;

public void actionPerformed(ActionEvent a_e)

{

summa=Account.balance; repaint();

}

public void paint(Graphics g)

{

setBackground(Color.pink); g.setColor(Color.white) ;

g.drawString("Your Account is:"+summa,100,100);

}

}

class Account {

static int balance=10000;

static public void putmoney(int amount)

{

balance=balance+amount;

}

}

class mythread extends Thread {

int sum, i; public void run()

{

while(true)

{

if (Math.random()>0.4)

{ i=l; } else {i=-l; } try

{sleep(100);} catch(Exception err)

{System.out.println(""+err) ; }

Account.putmoney((int) (i*Math.random()*100));

Пусть требуется перерисовывать окно апплета по инициативе не кнопки, а потока Для этого нужно динамически вызывать метод repaint () апплета. Попытки написать вызов типа myap- plet.repaint () либо myapplet.paint() приведут нас к неразрешимой проблеме, связанной с тем, что метод repaint () объявлен как static. Напомним, что если метод объявлен как static, то и все его переменные должны быть static. Проблема состоит в том, что в вызове myappiet. repaint () myappiet — есть имя класса, а не объекта. А ссылки на класс всегда предполагают тип static.

Имеется иная возможность — породить апплет-поток, т. e. апплет, совмещающий в себе поток с его методами и главным методом run (). Рассмотрите тот же пример, но без кнопки (листинг 2.19).

Листинг 2.19. Запуск потока без кнопки

import java.awt.*; import java.applet.*; import java.awt.event.*;

public class myapplet2 extends Applet implements Runnable

Thread myth; int i,summa=0;

public void init()

myth=new Thread(this); myth.start() ;

public void paint(Graphics g)

setBackground(Color.pink); g.setColor(Color.white);

public void run()

{

while(true)

{

if (Math.random()>0.4)

{i=l;} else {i=-l;} try

{myth.sleep(1000);} catch(Exception err)

{System.out.println(""+err) ; } summa=summa+((int)  (i *Math.random()*10 0));

repaint();

}

}

}

Поток myth, созданный в апплете, имеет доступ к методу paint () апплета и осуществляет его вызов в теле метода run ():

public void run()

{

{

while(true)

{

if (Math.random()>0.4)

{i=l;} else {i=-l;} try

{myth.sleep(1000);} catch(Exception err)

{System.out.println(""+err) ; } summa=summa+((int)  (i *Math.random()*10 0));

Такой способ реализации потоков в апплете позволяет динамически перерисовывать апплет в соответствии с логикой потока. Это дает возможность получать эффекты типа бегущей строки, мерцаний, смены рисунков и пр.

Источник: Герман О. B., Герман Ю. О., Программирование на Java и C# для студента. — СПб.: БХВ-Петербург, 2005. — 512 c.: ил.

Вы можете следить за любыми ответами на эту запись через RSS 2.0 ленту. Вы можете оставить ответ, или trackback с вашего собственного сайта.

Оставьте отзыв

XHTML: Вы можете использовать следующие теги: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

 
Rambler's Top100