Философия Java3
Шрифт:
public String toStringO {
return String, format С [n$-3d]\ priority) + " Task " + id;
}
public String summaryО {
return "(" + id + ":" + priority + ")";
}
public static class EndSentinel extends PrioritizedTask { private ExecutorService exec; public EndSentinel(ExecutorService e) {
super(-l); // Минимальный приоритет в этой программе
exec = e;
public void run {
int count = 0;
for(PrioritizedTask pt : sequence) { printnb(pt.summaryO), if(++count % 5 == 0) printO.
}
printO;
print (this + " Calling shutdownNowO"); exec.shutdownNowO.
}
}
}
class PrioritizedTaskProducer implements Runnable { private Random rand = new Random(47); private Queue<Runnable> queue; private ExecutorService exec; public PrioritizedTaskProducer(
Queue<Runnable> q, ExecutorService e) { queue = q;
exec = e; // Используется для EndSentinel
}
public void run {
// Неограниченная очередь без блокировки. // Быстрое заполнение случайными приоритетами: for(int i = 0; i < 20; i++) {
queue.add(new PrioritizedTask(rand.nextInt(10))); Thread.yieldO;
}
// Добавление высокоприоритетных задач: try {
for(int i = 0; i < 10; i++) {
TimeUnit.MILLISECONDS.sleep(250); queue.add(new PrioritizedTask(lO)).
}
// Добавление заданий, начиная с наименьших приоритетов: for(int i = 0; i < 10; i++)
queue.add(new PrioritizedTask(i)); // Предохранитель для остановки всех задач: queue.add(new PrioritizedTask EndSentinel(exec)); } catchdnterruptedException e) {
// Приемлемый вариант выхода
}
print("Завершение PrioritizedTaskProducer");
}
}
class PrioritizedTaskConsumer implements Runnable { private PriorityBlockingQueue<Runnable> q; public PrioritizedTaskConsumer(
PriorityBlockingQueue<Runnable> q) { this.q = q;
}
public void run {
while('Thread interruptedO)
// Использование текущего потока для запуска задачи q.takeO run. } catch(InterruptedException e) {
// Приемлемый вариант выхода
}
print("Завершение PrioritizedTaskConsumer").
}
}
public class PriorityBlockingQueueDemo {
public static void main(String[] args) throws Exception { Random rand = new Random(47);
ExecutorService exec = Executors newCachedThreadPoolО, PriorityBlockingQueue<Runnable> queue =
new PriorityBlockingQueue<Runnable>; exec execute(new PrioritizedTaskProducer(queue. exec)), exec execute(new PrioritizedTaskConsumer(queue)),
}
} ///:-
Как и в предыдущем примере, последовательность создания объектов PrioritizedTask сохраняется в контейнере List sequence для сравнения с фактическим порядком выполнения. Метод run делает небольшую паузу, а затем выводит информацию об объекте, а предохранитель EndSentinel выполняет те же функции, что и прежде.
PrioritizedTaskProducer и PrioritizedTaskConsumer связываются друг с другом через PriorityBlockingQueue. Так как сам блокирующий характер очереди обеспечивает всю необходимую синхронизацию, явная синхронизация не нужна — при чтении вам не нужно думать о том, содержит ли очередь элементы, потому что при отсутствии элементов очередь просто заблокирует читающую сторону.
Управление оранжереей на базе ScheduledExecutor
В главе 10 была представлена система управления гипотетической оранжереей, которая включала (отключала) различные устройства и регулировала их работу. Происходящее можно преобразовать в контекст многозадачности: каждое событие оранжереи представляет собой задачу, запускаемую в заранее заданное время. Класс ScheduledThreadPoolExecutor предоставляет именно тот сервис, который необходим для решения задачи. Используя методы schedule (однократный запуск задачи) или scheduleAtFixedRate (повторение задачи с постоянным промежутком), мы создаем объекты Runnable, которые должны запуститься в положенное время. Сравните это решение с тем, что приведено в главе 10, и посмотрите, насколько оно упрощается благодаря готовой функциональности ScheduledThreadPoolExecutor:
//: concurrency/GreenhouseScheduler.java
// Новая реализация innerclasses/GreenhouseController.java
// с использованием ScheduledThreadPoolExecutor.
// {Args- 5000}
import java.util.concurrent.*,
import java.util *;
public class GreenhouseScheduler {
private volatile boolean light = false, private volatile boolean water = false; private String thermostat = "Day", public synchronized String getThermostatO { return thermostat,
}
public synchronized void setThermostat(String value) { thermostat = value;
}
ScheduledThreadPoolExecutor scheduler =
new ScheduledThreadPoolExecutor(10), public void schedule(Runnable event, long delay) {
scheduler schedule(event,delay.TimeUnit MILLISECONDS);
}
public void
repeat(Runnable event, long i niti alDel ay, long period) { scheduler scheduleAtFixedRate(
event, i niti alDel ay. period, TimeUnit MILLISECONDS);
}
class LightOn implements Runnable { public void run {
// Сюда помещается аппаратный вызов, выполняющий // физическое включение света System out.printin("Свет включен"); light = true;
}
}
class LightOff implements Runnable { public void run {
// Сюда помещается аппаратный вызов, выполняющий // физическое выключение света. System.out.printin("Свет выключен"), light = false,
}
}
class WaterOn implements Runnable { public void run {
// Здесь размещается код включения // системы полива.
System out printlnC"Полив включен"); water = true;
}
}
class WaterOff implements Runnable { public void run О {
// Здесь размещается код выключения // системы полива
System out.printin("Полив выключен"); water = false,
}
}
class ThermostatNight implements Runnable { public void run {
// Здесь размещается код управления оборудованием System.out.ргШ1п("Включение ночного режима"); setThermostat("Ho4b"), } продолжение &
}
class ThermostatDay implements Runnable { public void run {
// Здесь размещается код управления оборудованием System out рпп^пСВключение дневного режима"), setThermostatCfleHb"),