tempDirecti on = -tempDirecti on; // Сохранить предыдущее значение: lastTemp = lastTemp +
tempDi recti on * (1 Of + rand.nextFloatO); if(rand.nextlnt(5) == 4)
humidityDirecti on = -humidityDirecti on; lastHumidity = lastHumidity +
humidityDi recti on * rand.nextFloatO; // Объект Calendar необходимо клонировать, иначе // все DataPoint будут содержать ссылки // на одно и то же lastTime. // Для базового объекта - такого, как Calendar -// вызова cloneO вполне достаточно, data.add(new DataPoint((Calendar)1astTime.cloneO. lastTemp. lastHumidity));
}
}
}
public static void main(String[] args) {
GreenhouseScheduler gh = new GreenhouseSchedulerO;
gh.schedule(gh.new TerminateO. 5000);
// Former "Restart" class not necessary:
gh.repeat(gh.new BellO. 0. 1000);
gh.repeat(gh.new ThermostatNightО. 0. 2000);
gh. repeat (gh. new LightOnO, 0. 200);
gh. repeat (gh. new LightOffO. 0. 400);
gh.repeat(gh.new WaterOn0. 0, 600);
gh. repeat (gh. new WaterOffO. 0. 800);
gh.repeat(gh.new ThermostatDayO. 0. 1400);
gh.repeat(gh.new CollectDataO. 500. 500).
}
} ///:-
В этой версии, помимо реорганизации кода, добавляется новая возможность: сбор данных о температуре и влажности в оранжерее. Объект DataPoint содержит и выводит одну точку данных, а запланированная задача CollectData генерирует данные имитации и включает их в List
Обратите внимание на ключевые слова volatile и synchronized; благодаря им задачи не мешают работе друг друга. Все методы контейнера List с элементами DataPoint синхронизируются с использованием метода synchronizedList() библиотеки java. u til. Со lie cti о n s при создании List.
Семафоры
При обычной блокировке доступ к ресурсу в любой момент времени разрешается только одной задаче.
В качестве примера рассмотрим концепцию
// concurrency/Pool java
// Использование Semaphore в Pool ограничивает количество // задач, которые могут использовать ресурс import java util concurrent *. import java util *,
public class Pool
private List
// Предполагается наличие конструктора по умолчанию items add(classObject newInstanceO). } catch(Exception e) {
throw new RuntimeException(e);
}
}
public T checkout О throws InterruptedException { available acquireO; return getltemO,
}
public void checkIn(T x) { if(releaseltem(x))
available releasee);
}
private synchronized T getltemO {
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 был освобожден
}
В этой упрощенной форме конструктор использует newlnstance() для заполнения пула объектами. Если вам понадобится новый объект, вызовите check-Out(); завершив работу с объектом, передайте его checkln().
Логический массив checkedOut отслеживает выданные объекты. Для управления его содержимым используются методы getltem() и releaseltem(). В свою очередь, эти методы защищены семафором available, поэтому в checkOut() семафор available блокирует дальнейшее выполнение при отсутствии семафорных разрешений (то есть при отсутствии объектов в пуле). Метод checkln() проверяет действительность возвращаемого объекта, и, если объект действителен, разрешение возвращается семафору.
Для примера мы воспользуемся классом 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.
}
}