русс | укр

Языки программирования

ПаскальСиАссемблерJavaMatlabPhpHtmlJavaScriptCSSC#DelphiТурбо Пролог

Компьютерные сетиСистемное программное обеспечениеИнформационные технологииПрограммирование

Все о программировании


Linux Unix Алгоритмические языки Аналоговые и гибридные вычислительные устройства Архитектура микроконтроллеров Введение в разработку распределенных информационных систем Введение в численные методы Дискретная математика Информационное обслуживание пользователей Информация и моделирование в управлении производством Компьютерная графика Математическое и компьютерное моделирование Моделирование Нейрокомпьютеры Проектирование программ диагностики компьютерных систем и сетей Проектирование системных программ Системы счисления Теория статистики Теория оптимизации Уроки AutoCAD 3D Уроки базы данных Access Уроки Orcad Цифровые автоматы Шпаргалки по компьютеру Шпаргалки по программированию Экспертные системы Элементы теории информации

Public void


Дата добавления: 2015-06-12; просмотров: 890; Нарушение авторских прав


repeat(Runnable event, long initialDelay, long period) {

scheduler.scheduleAtFixedRate(

event, initialDelay, period, TimeUnit.MILLISECONDS);

}

class LightOn implements Runnable {

public void run() {

// Put hardware control code here to

// physically turn on the light.

System.out.println("Turning on lights");

light = true;

}

}

class LightOff implements Runnable {

public void run() {

// Put hardware control code here to

// physically turn off the light.

System.out.println("Turning off lights");

light = false;

}

}

class WaterOn implements Runnable {

public void run() {

// Put hardware control code here.

System.out.println("Turning greenhouse water on");

water = true;

}

}

class WaterOff implements Runnable {

public void run() {

// Put hardware control code here.

System.out.println("Turning greenhouse water off");

water = false;

}

}

class ThermostatNight implements Runnable {

public void run() {

// Put hardware control code here.

System.out.println("Thermostat to night setting");

setThermostat("Night");

}

}

class ThermostatDay implements Runnable {

public void run() {

// Put hardware control code here.

System.out.println("Thermostat to day setting");

setThermostat("Day");

}

}

class Bell implements Runnable {

public void run() { System.out.println("Bing!"); }

}

class Terminate implements Runnable {

public void run() {

System.out.println("Terminating");

scheduler.shutdownNow();

// Must start a separate task to do this job,

// since the scheduler has been shut down:

new Thread() {

public void run() {

for(DataPoint d : data)

System.out.println(d);

}

}.start();



}

}

// New feature: data collection

static class DataPoint {

final Calendar time;

final float temperature;

final float humidity;

public DataPoint(Calendar d, float temp, float hum) {

time = d;

temperature = temp;

humidity = hum;

}

public String toString() {

return time.getTime() +

String.format(

" temperature: %1$.1f humidity: %2$.2f",

temperature, humidity);

}

}

private Calendar lastTime = Calendar.getInstance();

{ // Adjust date to the half hour

lastTime.set(Calendar.MINUTE, 30);

lastTime.set(Calendar.SECOND, 00);

}

private float lastTemp = 65.0f;

private int tempDirection = +1;

private float lastHumidity = 50.0f;

private int humidityDirection = +1;

private Random rand = new Random(47);

List<DataPoint> data = Collections.synchronizedList(

new ArrayList<DataPoint>());

class CollectData implements Runnable {

public void run() {

System.out.println("Collecting data");

synchronized(GreenhouseScheduler.this) {

// Pretend the interval is longer than it is:

lastTime.set(Calendar.MINUTE,

lastTime.get(Calendar.MINUTE) + 30);

// One in 5 chances of reversing the direction:

if(rand.nextInt(5) == 4)

tempDirection = -tempDirection;

// Store previous value:

lastTemp = lastTemp +

tempDirection * (1.0f + rand.nextFloat());

if(rand.nextInt(5) == 4)

humidityDirection = -humidityDirection;

lastHumidity = lastHumidity +

humidityDirection * rand.nextFloat();

// Calendar must be cloned, otherwise all

// DataPoints hold references to the same lastTime.

// For a basic object like Calendar, clone() is OK.

data.add(new DataPoint((Calendar)lastTime.clone(),

lastTemp, lastHumidity));

}

}

}

public static void main(String[] args) {

GreenhouseScheduler gh = new GreenhouseScheduler();

gh.schedule(gh.new Terminate(), 5000);

// Former "Restart" class not necessary:

gh.repeat(gh.new Bell(), 0, 1000);

gh.repeat(gh.new ThermostatNight(), 0, 2000);

gh.repeat(gh.new LightOn(), 0, 200);

gh.repeat(gh.new LightOff(), 0, 400);

gh.repeat(gh.new WaterOn(), 0, 600);

gh.repeat(gh.new WaterOff(), 0, 800);

gh.repeat(gh.new ThermostatDay(), 0, 1400);

gh.repeat(gh.new CollectData(), 500, 500);

}

} /* (Execute to see output) *///:~

В этой версии, помимо реорганизации кода, добавляется новая возможность: сбор данных о температуре и влажности в оранжерее. Объект DataPoint содержит и выводит одну точку данных, а запланированная задача CollectData генерирует данные имитации и включает их вList<DataPoint> при каждом запуске.

Обратите внимание на ключевые слова volatile и synchronized; благодаря им задачи не мешают работе друг друга. Все методы контейнера List с элементами DataPoint синхронизируются с использованием метода synchronizedList() библио­теки java.util.Соllectiоns при создании List.

 

Семафоры

При обычной блокировке доступ к ресурсу в любой момент времени разрешается только одной задаче. Семафор со счетчиком позволяет n задачам одновременно обращаться к ресурсу. Можно считать, что семафор «выдает разрешения» на использование ресурса, хотя никаких реальных объектов разрешений в этой схеме нет. В качестве примера рассмотрим концепцию пула объектов: объекты, входящие в пул, «выдаются» для использования, а затем снова возвращаются в пул после того, как пользователь закончит работу с ними. Эта функциональность инкапсулируется в параметризованном классе:

//: concurrency/Pool.java

// Использование Semaphore в Pool ограничивает количество

// задач, которые могут использовать ресурс.

import java.util.concurrent.*;

import java.util.*;

 

public class Pool<T> {

private int size;

private List<T> items = new ArrayList<T>();

private volatile boolean[] checkedOut;

private Semaphore available;

public Pool(Class<T> classObject, int size) {

this.size = size;

checkedOut = new boolean[size];

available = new Semaphore(size, true);

// Заполнение пула объектами :

for(int i = 0; i < size; ++i)

try {

// Предполагается наличие конструктора по умолчанию:

items.add(classObject.newInstance());

} catch(Exception e) {

throw new RuntimeException(e);

}

}

public T checkOut() throws InterruptedException {

available.acquire();

return getItem();

}

public void checkIn(T x) {

if(releaseItem(x))

available.release();

}

private synchronized T getItem() {

for(int i = 0; i < size; ++i)

if(!checkedOut[i]) {

checkedOut[i] = true;

return items.get(i);

}

return null; // Семафор предотвращает переход в зту точку

}

private synchronized boolean releaseItem(T item) {

int index = items.indexOf(item);

if(index == -1) return false; // Отсутствует в списке

if(checkedOut[index]) {

checkedOut[index] = false;

return true;

}

return false; // He был освобожден

}

}

В этой упрощенной форме конструктор использует newInstance() для заполнения пула объектами. Если вам понадобится новый объект, вызовите checkOut(); завершив работу с объектом, передайте его checkIn().

Логический массив checkedOut отслеживает выданные объекты. Для управления его содержимым используются методы getItem() и releaseItem(). В свою очередь, эти методы защищены семафором available, поэтому в checkOut() семафор available блокирует дальнейшее выполнение при отсутствии семафорных разрешений (то есть при отсутствии объектов в пуле). Метод checkIn() проверяет действительность возвращаемого объекта, и, если объект действителен, разрешение возвращается семафору.

Для примера мы воспользуемся классом Fat. Создание объектов этого класса является высокозатратной операцией, а на выполнение конструктора уходит много времени:

//: concurrency/Fat.java

// Объекты, создание которых занимает много времени.

 

public class Fat {

private volatile double d; // Предотвращает оптимизацию

private static int counter = 0;

private final int id = counter++;

public Fat() {

// Затратная, прервываемая операция:

for(int i = 1; i < 10000; i++) {

d += (Math.PI + Math.E) / (double)i;

}

}

public void operation() { System.out.println(this); }

public String toString() { return "Fat id: " + id; }

}

Мы создадим пул объектов Fat, чтобы свести к минимуму затраты на выполнение конструктора. Для тестирования класса Pool будет создана задача, которая забирает объекты Fat для использования, удерживает их в течение некоторого времени, а затем возвращает обратно:

//: concurrency/SemaphoreDemo.java

// Тестирование класса Pool

import java.util.concurrent.*;

import java.util.*;

import static net.mindview.util.Print.*;

 

// Задача для получения ресурса из пула:

class CheckoutTask<T> implements Runnable {

private static int counter = 0;

private final int id = counter++;

private Pool<T> pool;

public CheckoutTask(Pool<T> pool) {

this.pool = pool;

}

public void run() {

try {

T item = pool.checkOut();

print(this + "checked out " + item);

TimeUnit.SECONDS.sleep(1);

print(this +"checking in " + item);

pool.checkIn(item);

} catch(InterruptedException e) {

// Приемлемый способ завершения

}

}

public String toString() {

return "CheckoutTask " + id + " ";

}

}

 

public class SemaphoreDemo {

final static int SIZE = 25;

public static void main(String[] args) throws Exception {

final Pool<Fat> pool =

new Pool<Fat>(Fat.class, SIZE);

ExecutorService exec = Executors.newCachedThreadPool();

for(int i = 0; i < SIZE; i++)

exec.execute(new CheckoutTask<Fat>(pool));

print("All CheckoutTasks created");

List<Fat> list = new ArrayList<Fat>();

for(int i = 0; i < SIZE; i++) {

Fat f = pool.checkOut();

printnb(i + ": main() thread checked out ");

f.operation();

list.add(f);

}

Future<?> blocked = exec.submit(new Runnable() {

public void run() {

try {

// Семафор предотвращает лишний вызов checkout.

// поэтому следующий вызов блокируется:

pool.checkOut();

} catch(InterruptedException e) {

print("checkOut() Interrupted");

}

}

});

TimeUnit.SECONDS.sleep(2);

blocked.cancel(true); // Выход из заблокированного вызова

print("Checking in objects in " + list);

for(Fat f : list)

pool.checkIn(f);

for(Fat f : list)

pool.checkIn(f); // Второй вызов checkIn игнорируется

exec.shutdown();

}

} /* (Execute to see output) *///:~

В коде main() создается объект Pool для хранения объектов Fat, после чего группа задач CheckoutTask начинает использовать Pool. Далее поток main() начинает выдавать объекты Fat, не возвращая их обратно. После того как все объекты пула будут выданы, семафор запрещает дальнейшие выдачи. Метод run() блокируется, и через две секунды вызывается метод cancel(). Лишние возвраты Pool игнорирует.

 

Exchanger

Класс Exchanger представляет собой «барьер», который меняет местами объекты двух задач. На подходе к барьеру задачи имеют один объект, а на выходе — объект, ранее удерживавшийся другой задачей. Объекты Exchanger обычно исполь­зуются в тех ситуациях, когда одна задача создает высокозатратные объекты, а другая задача эти объекты потребляет.

Чтобы опробовать на практике класс Exchanger, мы создадим задачу-поставщика и задачу-потребителя, которые благодаря параметризации и генераторам могут работать с объектами любого типа. Затем эти параметризованные задачи будут применены к классу Fat.ExchangerProducer и ExchangerConsumer меняют местами List<T>; при вызове метода Exchanger.exchange() вызов блокируется до тех пор, пока парная задача не вызовет свой метод exchange(), после чего оба метода exchange() завершаются, а контейнеры List<T>меняются местами:

//: concurrency/ExchangerDemo.java

import java.util.concurrent.*;

import java.util.*;

import net.mindview.util.*;

 

class ExchangerProducer<T> implements Runnable {

private Generator<T> generator;

private Exchanger<List<T>> exchanger;

private List<T> holder;

ExchangerProducer(Exchanger<List<T>> exchg,

Generator<T> gen, List<T> holder) {

exchanger = exchg;

generator = gen;

this.holder = holder;

}

public void run() {

try {

while(!Thread.interrupted()) {

for(int i = 0; i < ExchangerDemo.size; i++)

holder.add(generator.next());

// Заполненный контейнер заменяется пустым::

holder = exchanger.exchange(holder);

}

} catch(InterruptedException e) {

// Приемлемый способ завершения.

}

}

}

 

class ExchangerConsumer<T> implements Runnable {

private Exchanger<List<T>> exchanger;

private List<T> holder;

private volatile T value;

ExchangerConsumer(Exchanger<List<T>> ex, List<T> holder){

exchanger = ex;

this.holder = holder;

}

public void run() {

try {

while(!Thread.interrupted()) {

holder = exchanger.exchange(holder);

for(T x : holder) {

value = x; // Выборка значения

holder.remove(x); // Нормально для CopyOnWriteArrayList

}

}

} catch(InterruptedException e) {

// Приемлемый способ завершения.

}

System.out.println("Final value: " + value);

}

}

 

public class ExchangerDemo {

static int size = 10;

static int delay = 5; // Секунды

public static void main(String[] args) throws Exception {

if(args.length > 0)

size = new Integer(args[0]);

if(args.length > 1)

delay = new Integer(args[1]);

ExecutorService exec = Executors.newCachedThreadPool();

Exchanger<List<Fat>> xc = new Exchanger<List<Fat>>();

List<Fat>

producerList = new CopyOnWriteArrayList<Fat>(),

consumerList = new CopyOnWriteArrayList<Fat>();

exec.execute(new ExchangerProducer<Fat>(xc,

BasicGenerator.create(Fat.class), producerList));

exec.execute(

new ExchangerConsumer<Fat>(xc,consumerList));

TimeUnit.SECONDS.sleep(delay);

exec.shutdownNow();

}

}

<spoiler text="Output:"> (Sample)

Final value: Fat id: 29999

</spoiler> В методе main() для обеих задач создается один объект Exchanger, а для перестановки создаются два контейнера CopyOnWriteArrayList. Эта разновидность List нормально переносит вызов метода remove() при перемещении по списку, не вы­давая исключенияConcurrentModificationException.

ExchangerProducer заполняет список, а затем меняет местами заполненный список с пустым, передаваемым от ExchangerConsumer. Благодаря Exchanger заполнение списка происходит одно­временно с использованием уже заполненного списка.

 

Моделирование

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

Примеры HorseRace.java и GreenhouseScheduler.java, приведенные ранее, тоже можно считать своего рода имитаторами.



<== предыдущая лекция | следующая лекция ==>
PriorityBlockingQueue | Модель кассира


Карта сайта Карта сайта укр


Уроки php mysql Программирование

Онлайн система счисления Калькулятор онлайн обычный Инженерный калькулятор онлайн Замена русских букв на английские для вебмастеров Замена русских букв на английские

Аппаратное и программное обеспечение Графика и компьютерная сфера Интегрированная геоинформационная система Интернет Компьютер Комплектующие компьютера Лекции Методы и средства измерений неэлектрических величин Обслуживание компьютерных и периферийных устройств Операционные системы Параллельное программирование Проектирование электронных средств Периферийные устройства Полезные ресурсы для программистов Программы для программистов Статьи для программистов Cтруктура и организация данных


 


Не нашли то, что искали? Google вам в помощь!

 
 

© life-prog.ru При использовании материалов прямая ссылка на сайт обязательна.

Генерация страницы за: 0.068 сек.