Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых

Microsoft Visual J++. Создание приложений и аплетов на языке Java. Часть 2

© Александр Фролов, Григорий Фролов
Том 32, М.: Диалог-МИФИ, 1997, 288 стр.

[Назад] [Содеожание] [Дальше]

Приложение Synchro

Для иллюстрации способа синхронизации задач с помощью методов wait и notify мы подготовили приложение Synchro. Внешне окно аплета этого приложения выглядит точно так же, как и окно аплета Rectangles (рис. 1.2).

Напомним, что приложение Rectangles постоянно рисует закрашенные прямоугольники случайного размера, расположения и цвета, для чего в методе run организован бесконечный цикл с задержкой.

Приложение Synchro решает ту же самую задачу немного другим способом. Оно создает две задачи. Первая задача рисует в цикле прямоугольники, однако вместо задержки она ожидает извещение от другой задачи, вызывая для этого функцию wait. Вторая задача, опять же в цикле, создает извещения, вызывая с задержкой метод notify. Таким образом, вторая задача как бы управляет работой первой задачи.

Исходные тексты приложения

Исходные тексты приложения Synchro приведены в листинге 1.11.

Листинг 1.11. Файл Synchro\Synchro.javal


// =========================================================
// Демонстрация синхронизации двух задач
//
// (C) Фролов А.В, 1997
//
// E-mail: frolov@glas.apc.org
// WWW:    http://www.glasnet.ru/~frolov
//            или
//         http://www.dials.ccas.ru/frolov
// =========================================================
import java.applet.*;
import java.awt.*;

// =========================================================
// Основной класс аплета
// =========================================================
public class Synchro extends Applet
{
  // Ссылка на задачу рисования прямоугольников
  DrawRectangles m_DrawRectThread = null;

  // Ссылка на задачу, периодически разблокирующую задачу
  // рисования прямоугольников
  NotifyTask m_NotifyTaskThread = null;

  // -------------------------------------------------------
  // getAppletInfo
  // Метод, возвращающей строку информации об аплете
  // -------------------------------------------------------
  public String getAppletInfo()
  {
    return "Name: Synchro\r\n" +
      "Author: Alexandr Frolov\r\n" +
      "E-mail: frolov@glas.apc.org" +
      "WWW:    http://www.glasnet.ru/~frolov" +
      "Created with Microsoft Visual J++ Version 1.0";
  }

  // -------------------------------------------------------
  // paint
  // Метод paint, выполняющий рисование в окне аплета
  // -------------------------------------------------------
  public void paint(Graphics g)
  {
    // Определяем текущие размеры окна аплета
    Dimension dimAppWndDimension = size();
    
    // Выбираем в контекст отображения желтый цвет
    g.setColor(Color.yellow);
    
    // Закрашиваем внутреннюю область окна аплета
    g.fillRect(0, 0, 
      dimAppWndDimension.width  - 1, 
      dimAppWndDimension.height - 1);

    // Выбираем в контекст отображения черный цвет
    g.setColor(Color.black);

    // Рисуем рамку вокруг окна аплета
    g.drawRect(0, 0, 
      dimAppWndDimension.width  - 1, 
      dimAppWndDimension.height - 1);
  }

  // -------------------------------------------------------
  // start
  // Метод вызывается при первом отображении окна аплета
  // -------------------------------------------------------
  public void start()
  {
    if (m_DrawRectThread == null)
    {
      m_DrawRectThread = new DrawRectangles(this);
      m_DrawRectThread.start();
    }

    if (m_NotifyTaskThread == null)
    {
      // Создаем задачу, передавая ей ссылку на
      // задачу рисования прямоугольников, которую
      // необходимо периодически разблокировать
      m_NotifyTaskThread = new NotifyTask(m_DrawRectThread);
      m_NotifyTaskThread.start();
    }
  }
	
  // -------------------------------------------------------
  // stop
  // Метод вызывается, когда окно аплета исчезает с экрана
  // -------------------------------------------------------
  public void stop()
  {
    if (m_DrawRectThread != null)
    {
      m_DrawRectThread.stop();
      m_DrawRectThread = null;
    }

    if (m_NotifyTaskThread != null)
    {
      m_NotifyTaskThread.stop();
      m_NotifyTaskThread = null;
    }
  }
}

// =========================================================
// Класс задачи для рисования прямоугольников
// =========================================================
class DrawRectangles extends Thread
{
  // Контекст отображения окна аплета
  Graphics g;

  // Размеры окна аплета
  Dimension dimAppWndDimension;

  // -------------------------------------------------------
  // DrawRectangles
  // Конструктор класса DrawRectangles
  // -------------------------------------------------------
  public DrawRectangles(Applet Appl)
  {
    // Получаем и сохраняем контекст отображения
    g = Appl.getGraphics();

    // Определяем текущие размеры окна аплета
    dimAppWndDimension = Appl.size();
  }

  // -------------------------------------------------------
  // run
  // Метод, который работает в рамках отдельной задачи
  // Он рисует в окне аплета прямоугольники случайного
  // цвета, размера и расположения
  //
  // Этот метод должен быть определен как synchronized
  // -------------------------------------------------------
  public synchronized void run()
  {
    while (true)
    {
      int x, y, width, height;
      int rColor, gColor, bColor;
      
      // Выбираем случайным образом размеры
      // и расположение рисуемого прямоугольника
      x = (int)(dimAppWndDimension.width * 
          Math.random());
      y = (int)(dimAppWndDimension.height * 
          Math.random());
      width  = (int)(dimAppWndDimension.width * 
          Math.random()) / 2;
      height = (int)(dimAppWndDimension.height * 
          Math.random()) / 2;
      
      // Выбираем случайный цвет для рисования 
      // прямоугольника
      rColor = (int)(255 * Math.random());
      gColor = (int)(255 * Math.random());
      bColor = (int)(255 * Math.random());

      // Устанавливаем выбранный цвет в контексте 
      // отображения
      g.setColor(new Color(rColor, gColor, bColor));

      // Рисуем прямоугольник
      g.fillRect(x, y, width, height);

      // Переводим задачу в сотояние ожидания, в котором
      // она будет находиться до тех пор, пока не будет
      // разблокирована задачей класса NotifyTask
      try
      {
        Thread.wait();
      }
      catch (InterruptedException e)
      {
      }
    }
  }
}

// =========================================================
// Класс задачи для периодического разблокирования
// задачи рисования прямоугольников
// =========================================================
class NotifyTask extends Thread
{
  // Ссылка на задачу, которую необходимо разблокировать
  Thread STask;

  // -------------------------------------------------------
  // Конструктор класса NotifyTask
  // -------------------------------------------------------
  public NotifyTask(Thread SynchroTask)
  {
    // Сохраняем ссылку на задачу, которую необходимо
    // разблокировать
    STask = SynchroTask;
  }

  // -------------------------------------------------------
  // run
  // Метод, который работает в рамках отдельной задачи и
  // периодически разблокирует задачу STask
  // -------------------------------------------------------
  public void run()
  {
    while (true)
    {
      // Выполняем задержку на 30 миллисекунд
      try
      {
        Thread.sleep(30);
      }
      catch (InterruptedException e)
      {
      }

      // Получаем объект STask в монопольное владение
      // и вызываем для него метод notify, 
      // разблокируя работу соотвестсвующей задачи
      synchronized(STask)
      {
        STask.notify();
      }
    }
  }
}

Файл документа HTML, созданный автоматически для нашего аплета, вы найдете в листинге 1.12.

Листинг 1.12. Файл Synchro\Synchro.html


<html>
<head>
<title>Synchro</title>
</head>
<body>
<hr>
<applet
    code=Synchro.class
    id=Synchro
    width=320
    height=240 >
</applet>
<hr>
<a href="Synchro.java">The source.</a>
</body>
</html>

Описание исходных текстов

Рассмотрим поля и самые важные методы, определенные в классах приложения Synchro.

Поля основного класса аплета

В основном классе аплета определены две ссылки m_DrawRectThread и m_NotifyTaskThread:


DrawRectangles m_DrawRectThread = null;
NotifyTask m_NotifyTaskThread = null;

Первая из них является ссылкой на объект класса DrawRectangles, определенный нами для задачи рисования прямоугольников. Вторая переменная представляет собой ссылку на объект класса NotifyTask, который создан для задачи, управляющей работой задачи рисования.

Метод start основного класса

Метод start создает и запускает на выполнение две задачи. Первая задача создается как объект класса DrawRectangles, вторая - как объект класса NotifyTask:


if (m_DrawRectThread == null)
{
  m_DrawRectThread = new DrawRectangles(this);
  m_DrawRectThread.start();
}
if (m_NotifyTaskThread == null)
{
  m_NotifyTaskThread = new NotifyTask(m_DrawRectThread);
  m_NotifyTaskThread.start();
}

При создании задачи рисования прямоугольников конструктору передается ссылка на аплет. Эта ссылка нужна задаче для определения размеров окна аплета и получения контекста отображения.

Конструктору класса NotifyTask передается ссылка на задачу, работой которой она будет управлять с помощью механизма ожидания извещений.

Метод stop основного класса

Когда пользователь покидает страницу с аплетом, метод stop останавливает работу обеих задач, вызывая для них метод stop из класса Thread:


if (m_DrawRectThread != null)
{
  m_DrawRectThread.stop();
  m_DrawRectThread = null;
}
if (m_NotifyTaskThread != null)
{
  m_NotifyTaskThread.stop();
  m_NotifyTaskThread = null;
}

Поля класса DrawRectangles

В поле g класса Graphics хранится контекст отображения окна аплета, определенный конструктором класса DrawRectangles.

Поле dimAppWndDimension хранит размеры окна аплета.

Конструктор класса DrawRectangles

Для получения контекста отображения окна аплета, ссылка на который передается через единственный параметр, конструктор класса DrawRectangles вызывает метод getGraphics:


public DrawRectangles(Applet Appl)
{
  g = Appl.getGraphics();
  dimAppWndDimension = Appl.size();
}

Размеры окна аплета определяются с помощью метода size.

Метод run класса DrawRectangles

Метод run вызывает метод wait для синхронизации с другой задачей, поэтому этот метод определен как синхронизированный с помощью ключевого слова synchronized:


public synchronized void run()
{
  . . .
}

Внутри метода run организован цикл рисования, который мы уже описывали. После рисования очередного прямоугольника метод run переходит в состояние ожидания извещения, вызывая метод wait:


try
{
  Thread.wait();
}
catch (InterruptedException e)
{
}

Поля класса NotifyTask

В классе NotifyTask мы определили одно поле STask класса Thread, которое хранит ссылку на задачу, работой которой управляет данный класс. Конструктор класса NotifyTask записывает сюда ссылку на задачу рисования прямоугольников.

Метод run класса NotifyTask

Метод run класса NotifyTask периодически разблокирует задачу рисования прямоугольников, вызывая для этого метод notify в цилке с задержкой 30 миллисекунд. Обращение к объекту STask, который хранит ссылку на задачу рисования прямоугольников, выполняется с использованием синхронизации:


synchronized(STask)
{
  STask.notify();
}
[Назад] [Содеожание] [Дальше]