250 likes | 611 Views
G53SRP: Clocks and Time in Java. Chris Greenhalgh School of Computer Science. Contents. The system clock Sleeping Absolute delays Time-outs on wait Java 1.5 extensions: TimeUnit, nanoTime Events, Timers and TimerTasks Book: Wellings 4.2 & 4.4. The System Clock.
E N D
G53SRP: Clocks and Time in Java Chris Greenhalgh School of Computer Science
Contents • The system clock • Sleeping • Absolute delays • Time-outs on wait • Java 1.5 extensions: TimeUnit, nanoTime • Events, Timers and TimerTasks • Book: Wellings 4.2 & 4.4
The System Clock • The JVM exposes a system clock: java.lang.System { static long currentTimeMillis();} • Also used by new java.util.Date(); to initialise to current time. • Returns milliseconds since midnight January 1st 1970 GMT (like “UNIX time”). • Depends on accuracy and granularity of underlying hardware clock • Accuracy = How close it is to the real time • Granularity = The size of the “tick” (e.g. clock step)Note: may be larger than nominal resolution (e.g. 10ms in Java) Try ClockGranularity.java
Starting time “Current” time Target end time “Busy” loop – Inefficient – “wastes” CPU Busy waiting delay public class BusyDelay { public static void main(String [] args) { long start = System.currentTimeMillis(); long delay = 1000; while (System.currentTimeMillis() < start+delay) ; } }
Sleep • The system allows a thread to perform a relative delay: java.lang.Thread { static void sleep(long millis);} • N.B. delay is a minimum – see later • JVM can map request to OS sleep • Avoids busy waiting – more efficient: clock-watching is delegated to JVM and thence OS Compare CPU utilisation for BusyDelay & SleepDelay
Relative delay time May be woken by Thread.interrupt()– see later notes Sleep delay public class SleepDelay { public static void main(String [] args) { long delay = 1000; try { Thread.sleep(delay); } catch(InterruptedException ie) { /*ignore*/ } } }
Thread executing Sleep Granularity Local drift Granularity difference between clock and sleep time Time specified by program Thread runnable here but not executing Interrupts disabled Time © Andy Wellings 2004 – from Wellings figure 4.1
Absolute delays • Clock granularity, pre-emption and compute time make exact timing of sleep and code impossible • Approximated by sleeping until (after) a specific target time
Granularity andpreemption time ignored Execution and preemption time ignored Drifting clock public class DriftingClock { public static void main(String [] args) { long delay = 1000; // 1 second = 1000 ms while(true) { try { Thread.sleep(delay); } catch(InterruptedException ie) { /*ignore*/ } System.out.println("Tick at "+ System.currentTimeMillis()); } } } Absolute time errors accumulate
N.B. integer arithmetic Absolute delay example public class SleepAbsoluteDelay { public static void main(String [] args) { long start = System.currentTimeMillis(); // next 10 second boundary long tenseconds = 10*1000; long end = ((start+tenseconds) / tenseconds)* tenseconds; long delay = end-start; try { Thread.sleep(delay); } catch(InterruptedException ie) { /*ignore*/ } long now = System.currentTimeMillis(); } }
Time-outs on wait() • Default wait() blocks thread indefinitely until notified • Possible to set maximum wait time: • java.lang.Object { void wait(long millis); void wait(long millis, long nanos);} • E.g. for • error detection (e.g. deadlock, message loss) • timed protocols
Timed-wait notes • wait(0) = wait(0,0) = wait() • Cannot distinguish time-out from notify • Neither raises an exception (unlike interrupt) • Consider notify “at the same time” as timeout • Just before => thread is woken by notify, waits for lock and returns just after timeout time • Just after => thread is woken by time-out, waits for lock and returns just after timeout time
See TimedWait.java // thread 1… synchronized(tw) { long start = System. currentTimeMillis(); try { tw.wait(5*1000); } catch (InterruptedException ie) {} System.out.println ("Done: " +(System.currentTimeMillis()-start)+"ms"); } // thread 2… long delay = 4000+(new java.util.Random()). nextInt(2000); try { Thread.sleep(delay); } catch(InterruptedException ie) {} synchronized(tw) { tw.notify(); } Should never be (much) more than 5000ms Timed-wait example
Java 1.5 extensions (JSR166) • Better support for time granularity java.lang.System { static long nanoTime();} • See also next slide • Other concurrency utilities: • java.util.concurrent, e.g. queues • java.util.concurrent.atomic – for lock-free thread-safe programming w. shared variables • java.util.concurrent.locks – various lock utility classes
java.util.concurrent.TimeUnit package java.util.concurrent;public final enum TimeUnit { // available granularitiesMICROSECONDS, MILLISECONDS, NANOSECONDS, SECONDS; // utilities to manipulate times long convert(long duration, TimeUnit units); long toNanos(long duration); // timed operations in this granularity void sleep(long timeout) throws InterruptedException; void timedWait(Object monitor, long timeout) throws InterruptedException; void timedJoin(Thread thread, long timeout) throws InterruptedException;} e.g. see SleepTimeUnitsDelay
Events, TimerTasks and Timers • A java.util.TimerTask is a Runnable object that represents a unit of work • E.g. a GUI redraw or update • A java.util.Timer represents a background thread that executes a set of TimerTasks non-concurrently: • Enforces order • Avoids overhead of multiple threads or thread per task
java.util.TimerTask package java.util;public abstract class TimerTask implements Runnable { protected TimerTask(); // cancel task before (next) run public boolean cancel(); // most recent release time public long scheduledExecutionTime(); // actual task code – override public abstract void run();}
java.util.Timer package java.util;public class Timer { Timer(); Timer(boolean isDaemon); void cancel(); // one-shot void schedule(TimerTask task, long delay); void schedule(TimerTask task, java.util.Date time); // repeating void schedule(TimerTask task, java.util.Date firstTime, long period); void schedule(TimerTask task, long delay, long period); void scheduleAtFixedRate(TimerTask task, java.util.Date firstTime, long period); void scheduleAtFixedRate(TimerTask task, long delay, long period);}
Timer example import java.util.Timer; import java.util.TimerTask; public class DriftingTimerClock { static class TickTask extends TimerTask { int count = 0; public void run() { System.out.println("Tick "+(count++)+"!"); } } public static void main(String [] args) { Timer timer = new Timer(); // in 1 second, every second timer.schedule(new TickTask(), 1000, 1000); } } To avoid drift use timer.scheduleAtFixedRate(…)
Summary • Access to the system clock can support simple timing • Thread.sleep allows efficient relative delays • Sleep time is a minimum • Care is needed to avoid cumulative errors/drift • wait() can have a timeout specified • But timeout and notify cannot be distinguished • java.util.Timer and TimerTask support sequential scheduling of one-shot and repeated tasks on a shared thread • Avoiding per-task thread overhead, • preventing concurrency between tasks