Лабораторная работа №1.

advertisement
Лабораторная работа №1.
Расширенные возможности создания многопоточных приложений
Цель работы: 1) научиться использовать расширенные возможности создания
многопоточных приложений на Java.
Продолжительность работы: 4 часа.
Теоретические сведения
Теоретические сведения и подробное описание очередей и исполнителей можно найти в
лекциях и по .адресу:
http://java.sun.com/docs/books/tutorial/essential/concurrency/highlevel.html
Пример использования очередей
В нижеприведенном примере симулируется ситуация, когда в какое-то хранилище
загружается что-то, и одновременно разгружается. В программе представлено два потока
(плюс один поток программы). Один поток загружает в хранилище объекты, а второй их
оттуда разгружает.
Хранилище имеет ограниченный рамер (константа STORAGE_SIZE). Если места в
хранилище нет, погрузчик ожидает освобождения места. С другой стороны, разгрузчик
ожидает наличие чего разгружать, если на складе пусто. При окончании загрузки (флаг
loadFinished) разгрузчик довыгружает остатки и завершает работу, при этом вместо
метода take используется метод poll, т.к.poll в случае если хранилище пусто, не ожидает
появления в нем чего-либо, а возвращает null.
Если использовать только take(), то по окончанию загрузки поток-разгрузчик
заблокируется навсегда. А если использовать только poll(), то в случае если разгрузка
происходит быстрее, чем погрузка, то поток преждевременно сообщит об окончании
загрузки и завершит работу, не окончив полностью процесс разгрузки.
public class Queues {
private static final int STORAGE_SIZE = 10;
private static final int GOODS_NUMBER = 30;
private ArrayBlockingQueue<Stuff> storage;
private boolean loadFinished;
public Queues()
{
storage = new ArrayBlockingQueue<Stuff>(STORAGE_SIZE);
}
public void start() {
// запускаем потоки погрузки и разгрузки
Thread loader = new Loader();
loader.start();
Thread unloader = new Unloader();
unloader.start();
try
{
loader.join(); // ждем окончания погрузки
} catch (InterruptedException e)
{
}
loadFinished = true; // устанавливаем флаг, что погрузка
закончилась
}
public class Loader extends Thread {
public void run()
{
try {
for (int i = 0; i < GOODS_NUMBER; i++) {
Thread.sleep(new Random().nextInt(300) + 100);
// загружаем новый товар
Stuff stuff = new Stuff(i+1);
storage.put(stuff);
System.out.println(String.format("Товар №%d
загружен", stuff.getNumber()));
}
} catch (InterruptedException e) {
}
System.out.println("Загрузка товаров окончена");
}
}
public class Unloader extends Thread {
public void run()
{
try {
while (!isInterrupted()) {
Stuff stuff;
// разгружаем товар
if (loadFinished)
stuff = storage.poll();
else
stuff = storage.take();
if (stuff == null) // разгузка закончилась и в
очереди больше ничего нет
break;
Thread.sleep(new Random().nextInt(700) + 200);
System.out.println(String.format("Товар №%d
разгружен", stuff.getNumber()));
}
} catch (InterruptedException e) {
}
System.out.println("Разгрузка товаров окончена");
}
}
public class Stuff {
private int number;
/**
* @param number
*/
public Stuff(int number)
{
super();
this.number = number;
}
public int getNumber()
{
return number;
}
}
public static void main(String[] args) {
new Queues().start();
}
}
Пример использования исполнителей
Исполнитель принимает на исполнение задачу, которая производится в отдельном потоке.
Если у исполнения есть результат, то его можно получить, используя интерфейс Future.
public class Execs {
public static class FactorialCalculator implements Callable<Long> {
private int n;
public FactorialCalculator(int n)
{
super();
this.n = n;
}
@Override
public Long call() throws Exception
{
long result = 1;
for (int i = 1; i < n; i++ ) {
result *= i;
}
return result;
}
}
public static void main(String[] args) {
int n = new Scanner(System.in).nextInt();
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<Long> result = executor.submit(new FactorialCalculator(n));
try
{
System.out.println("Результат: " + result.get());
} catch (InterruptedException e)
{
} catch (ExecutionException e)
{
e.printStackTrace();
}
executor.shutdown();
}
}
Задания
Вариант 1.
Реализовать программу, симулирующую процесс работы железнодорожного склада, на
котором может храниться один из трех видов товаров: сыпучие, жидкие и
скоропортящиеся.
К складу «подъезжает» ж/д состав с определенным количеством и типов вагонов и
ожидает погрузку товаров со склада. С другой стороны к складу «подъезжают»
автомобили с данными товарами, которые разгружаются на склад. Склад имеет
ограниченную вместимость по каждому из видов товаров.
Одновременно может разгружаться только один автомобиль каждого вида. Остальные
ожидают своей очереди.
Ж/д состав ожидает полную загрузку всех вагонов, остальные составы ждут своей
очереди.
Программа должна иметь графический интерфейс, схематично визуализирующую процесс
работы и следующие элементы, управляющие:

подъездом автомобиля с грузом пределенного типа

подъездом нового ж/д состава.
На экране должно отображаться события:

начало разгрузки автомобиля

окончания разгрузки автомобиля

начало загрузки состава

окончание загрузки состава.
Необходимо иметь ввиду, что вместимость вагонов и автомобилей различается.
Реализовать временные задержки для лучшей визуализации процесса.
Вариант 2.
Реализовать похожую программу, что и в варианте 1 с одним отличием, что разгрузка
происходит в обратном порядке — из ж/д состава в автомобили.
Вариант 3.
Реализовать похожую программу, что и в варианте 1 с одним отличием, что в случае
полной загрузки скоропортящихся товаров в ж/д состав, его загрузка считается
законченной.
Вариант 4.
а) Разработать программу-сервер, обрабатывающая запросы от клиентов по сети.
Протокол и данные запросов и ответов может быть произвольным. Если обработка
данных занимает слишком мало процессорного времени, то для большей наглядности в
обработчик запросов необходимо вставить временные задержки.
Программа-сервер должна иметь пул потоков фиксированного размера для обработки
запросов от клиента. Программа-сервер может не иметь графического интерфейса.
б) Разработать программу-клиента для тестирования сервера, устанавливающая с
сервером одновременно N соединений. Программа должна иметь графический интерфейс,
результаты, полученные от сервера должны выводиться пользователю.
В данных программах необходимо использовать исполнителей (Executors)
Download