Sh4d0wsPlyr
Sh4d0wsPlyr

Reputation: 968

How to change the duration of a Thread.sleep() already sleeping

I am looking for information on changing a Threads sleep pattern mid-sleep. Basically here is my situation laid out...

public void run() {
    while(running) {
        //Update Stuff...
        try {
            long time = System.currentTimeMillis() + interval;
            String dateFormatted = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss a").format(new Date(time));
            Thread.sleep(interval);
        } catch (InterruptedException e) {
            //Handle Errors...
        }
    }
}

So what I am doing is on program startup, it will take the interval (currently 60000), however the GUI has options to be able to change the interval (e.g. 1 hour, 2 hours, 3, etc). I can update just fine from the GUI and change the interval variable.

However when I change it, the thread is still sleeping and will wait until its finished, and update on the next iteration. What is the best way to interrupt this currently sleeping thread (or wake it up?). Also, I am concerned about making it "safe" as it will be running on a production server.

Any direction/guidance is awesome.

Upvotes: 2

Views: 2548

Answers (2)

user3707125
user3707125

Reputation: 3484

You can implement a simple solution through wait/notify.

Something like this:

class DurationSleeper {

    private final Object monitor = new Object();
    private long durationMillis = 0;

    public DurationSleeper(long duration, TimeUnit timeUnit) {
        setDuration(duration, timeUnit);
    }

    public void sleep() {
        long millisSlept = 0;

        while (true) {
            synchronized (monitor) {
                try {
                    long millisToSleep = durationMillis - millisSlept;
                    if (millisToSleep <= 0) {
                        return;
                    }
                    long sleepStartedInNanos = System.nanoTime(); // Not using System.currentTimeMillis - it depends on OS time, and may be changed at any moment (e.g. by daylight saving time)
                    monitor.wait(millisToSleep);
                    millisSlept += TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - sleepStartedInNanos);
                } catch (InterruptedException e) {
                    throw new RuntimeException("Execution interrupted.", e);
                }
            }
        }
    }

    public void setDuration(long newDuration, TimeUnit timeUnit) {
        synchronized (monitor) {
            this.durationMillis = timeUnit.toMillis(newDuration);
            monitor.notifyAll();
        }
    }
}

Upvotes: 3

tomasb
tomasb

Reputation: 1673

I wouldn't go with interrupt(), more like split sleep, lets say 1 minute and check if it is the time to wake up or sleep again. Overhead is next to nothing in such scenario.

Upvotes: 1

Related Questions