package com.dhemery.polling; import java.util.concurrent.TimeUnit; /** * <p> * An ticker that uses the system clock to reckon time. * The ticker has a duration and a tick size, both in milliseconds. * </p> * <p> * The ticker expires at its start time plus its duration. * </p> * <p> * Note that even after the ticker expires, * it will continue to tick when requested. * </p> */ public class SystemClockTicker implements Ticker { private static final long ONE_SECOND = 1000; private final long durationInMilliseconds; private final long tickSizeInMilliseconds; private long startTime; /** * Create a ticker with the given duration and a tick size of one second. */ public SystemClockTicker(long durationInMilliseconds) { this(durationInMilliseconds, ONE_SECOND); } /** * Create a ticker with the given duration and tick size. */ public SystemClockTicker(long durationInMilliseconds, long tickSizeInMilliseconds) { this.durationInMilliseconds = durationInMilliseconds; this.tickSizeInMilliseconds = tickSizeInMilliseconds; } @Override public boolean isExpired() { return elapsedTime() >= durationInMilliseconds; } @Override public void start() { startTime = now(); } @Override public void tick() { sleep(intervalUntilNextTick()); } @Override public String toString() { return String.format("duration %s tick size %s", durationInMilliseconds, tickSizeInMilliseconds); } private long elapsedTime() { return now() - startTime; } private long intervalUntilNextTick() { long timeElapsedSincePreviousTick = elapsedTime() % tickSizeInMilliseconds; return tickSizeInMilliseconds - timeElapsedSincePreviousTick; } private long now() { return System.currentTimeMillis(); } private void sleep(long durationInMilliseconds) { try { TimeUnit.MILLISECONDS.sleep(durationInMilliseconds); } catch (InterruptedException ignored) { } } }