Tuesday, August 5, 2014

DelayQueue Usage : Greenhouse Simulation

Thinking In Java Ex33 [Concurrency] :

Q. Modify GreenhouseScheduler.java so that it uses a DelayQueue instead of a ScheduledExecutor.

What we need to do is to know the duration (total no of times the task needs to execute) and the interval (time after which the task executes). So that we add that task to the queue duration/interval number of times, setting the delay time to be interval * (n+1) //n is the iteration number counter when the object is being added in a loop.

Code:

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 getThermostat() {
        return thermostat;
    }

    public synchronized void setThermostat(String value) {
        thermostat = value;
    }

    public static DelayQueue<Delayed> queue = new DelayQueue<>();
//    ScheduledThreadPoolExecutor scheduler
//            = new ScheduledThreadPoolExecutor(10);

    public static void schedule(Delayed event) {
        queue.add(event);
        //  scheduler.schedule(event, delay, TimeUnit.MILLISECONDS);
    }

    public static void repeat(Task event, long interval, long duration) {
        if (interval <= duration) {
            for (int i = 0; i < duration / interval; i++) {
                Task t = event.create(interval * (i + 1));
                queue.put(t);
            }
        }
    }

    abstract class Task implements Delayed {

        private long delay;
        private long trigger;

        Task(long delay) {
            this.delay = TimeUnit.NANOSECONDS.convert(delay, TimeUnit.MILLISECONDS);
            trigger = this.delay + System.nanoTime();
        }

        abstract Task create(long delay);

        @Override
        public long getDelay(TimeUnit unit) {
            return unit.convert(trigger - System.nanoTime(), TimeUnit.NANOSECONDS);
        }

        @Override
        public int compareTo(Delayed o) {
            Task that = (Task) o;
            if (trigger < that.trigger) {
                return -1;
            } else if (trigger > that.trigger) {
                return 1;
            } else {
                return 0;
            }
        }
    }

    class LightOn extends Task implements Runnable {

        LightOn() {
            super(0);
        }

        LightOn(long delay) {
            super(delay);
        }

        LightOn create(long delay) {
            return new LightOn(delay);
        }

        public void run() {
            // Put hardware control code here to
            // physically turn on the light.
            System.out.println("Turning on lights");
            light = true;
        }
    }

    class LightOff extends Task implements Runnable {

        LightOff() {
            super(0);
        }

        LightOff(long delay) {
            super(delay);
        }

        LightOff create(long delay) {
            return new LightOff(delay);
        }

        public void run() {
            // Put hardware control code here to
            // physically turn off the light.
            System.out.println("Turning off lights");
            light = false;
        }
    }

    class WaterOn extends Task implements Runnable {

        WaterOn() {
            super(0);
        }

        WaterOn(long delay) {
            super(delay);
        }

        WaterOn create(long delay) {
            return new WaterOn(delay);
        }

        public void run() {
            // Put hardware control code here.
            System.out.println("Turning greenhouse water on");
            water = true;
        }
    }

    class WaterOff extends Task implements Runnable {

        WaterOff() {
            super(0);
        }

        WaterOff(long delay) {
            super(delay);
        }

        WaterOff create(long delay) {
            return new WaterOff(delay);
        }

        public void run() {
            // Put hardware control code here.
            System.out.println("Turning greenhouse water off");
            water = false;
        }
    }

    class ThermostatNight extends Task implements Runnable {

        ThermostatNight() {
            super(0);
        }

        ThermostatNight(long delay) {
            super(delay);
        }

        ThermostatNight create(long delay) {
            return new ThermostatNight(delay);
        }

        public void run() {
            // Put hardware control code here.
            System.out.println("Thermostat to night setting");
            setThermostat("Night");
        }
    }

    class ThermostatDay extends Task implements Runnable {

        ThermostatDay() {
            super(0);
        }

        ThermostatDay(long delay) {
            super(delay);
        }

        ThermostatDay create(long delay) {
            return new ThermostatDay(delay);
        }

        public void run() {
            // Put hardware control code here.
            System.out.println("Thermostat to day setting");
            setThermostat("Day");
        }
    }

    class Bell extends Task implements Runnable {

        Bell() {
            super(0);
        }

        Bell(long delay) {
            super(delay);
        }

        Bell create(long delay) {
            return new Bell(delay);
        }

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

    class Terminate extends Task implements Runnable {

        Terminate() {
            super(0);
        }

        Terminate(long delay) {
            super(delay);
        }

        Terminate create(long delay) {
            return new Terminate(delay);
        }

        public void run() {
            System.out.println("Terminating");
            queue.clear();
            // 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 extends Task implements Runnable {

        CollectData() {
            super(0);
        }

        CollectData create(long delay) {
            return new CollectData(delay);
        }

        CollectData(long delay) {
            super(delay);
        }

        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) throws Exception {
        GreenhouseScheduler gh = new GreenhouseScheduler();

        repeat(gh.new Bell(), 1000, 4000);
        repeat(gh.new ThermostatNight(), 2000, 4000);
        repeat(gh.new LightOn(), 200, 4000);
        repeat(gh.new LightOff(), 400, 4000);
        repeat(gh.new WaterOn(), 600, 4000);
        repeat(gh.new WaterOff(), 800, 4000);
        repeat(gh.new ThermostatDay(), 1400, 4000);
        repeat(gh.new CollectData(), 500, 4000);
        queue.put(gh.new Terminate(5000));

        while (!queue.isEmpty()) {
            Runnable r = (Runnable) queue.take();
            r.run();
        }
    }
}

Output:

Turning on lights
Turning on lights
Turning off lights
Collecting data
Turning on lights
Turning greenhouse water on
Turning on lights
Turning off lights
Turning greenhouse water off
Bing!
Turning on lights
Collecting data
Turning on lights
Turning off lights
Turning greenhouse water on
Turning on lights
Thermostat to day setting
Collecting data
Turning on lights
Turning off lights
Turning greenhouse water off
Turning on lights
Turning greenhouse water on
Bing!
Thermostat to night setting
Turning on lights
Turning off lights
Collecting data
Turning on lights
Turning on lights
Turning off lights
Turning greenhouse water on
Turning greenhouse water off
Collecting data
Turning on lights
Turning on lights
Turning off lights
Thermostat to day setting
Bing!
Turning on lights
Turning greenhouse water on
Collecting data
Turning on lights
Turning off lights
Turning greenhouse water off
Turning on lights
Collecting data
Turning on lights
Turning off lights
Turning greenhouse water on
Turning on lights
Bing!
Thermostat to night setting
Turning on lights
Turning off lights
Turning greenhouse water off
Collecting data
Terminating
Tue Aug 05 09:00:00 IST 2014 temperature: 66.4 humidity: 50.05
Tue Aug 05 09:30:00 IST 2014 temperature: 68.0 humidity: 50.47
Tue Aug 05 10:00:00 IST 2014 temperature: 69.7 humidity: 51.42
Tue Aug 05 10:30:00 IST 2014 temperature: 70.8 humidity: 50.87
Tue Aug 05 11:00:00 IST 2014 temperature: 72.0 humidity: 50.32
Tue Aug 05 11:30:00 IST 2014 temperature: 73.2 humidity: 49.92
Tue Aug 05 12:00:00 IST 2014 temperature: 71.9 humidity: 49.81
Tue Aug 05 12:30:00 IST 2014 temperature: 70.1 humidity: 50.25

No comments:

Post a Comment