-
-
Save paulogaspar7/1810820 to your computer and use it in GitHub Desktop.
Unit testable `System.currentTimeMillis()`.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package util; | |
import java.util.concurrent.locks.LockSupport; | |
/** | |
* The Clock improves upon {@link System#currentTimeMillis()} in that it can be | |
* stopped and manually ticked forward. This is useful for testability. | |
* @author chris vest | |
*/ | |
public final class Clock { | |
private static volatile long now; | |
private static final Ticker ticker = new Ticker(); | |
private Clock() { /* static utility class */ } | |
/** | |
* Advance the clock to the current time. | |
* @return The new current time, in milliseconds since the epoch. | |
*/ | |
public static long tick() { | |
return now = System.currentTimeMillis(); | |
} | |
/** | |
* Advance the clock by exactly one millisecond, regardless of what the | |
* actual time may be. | |
* Note that this method is racy, and is technically only safe to call by | |
* a single thread at a time, and when the automatic ticking of the clock | |
* has been turned off. This method is only really useful for unit testing of | |
* time dependent code. | |
*/ | |
public static void inc() { | |
now++; | |
} | |
/** | |
* Get the value of the last tick. | |
* @return The "current" time recorded by the last tick. | |
*/ | |
public static long currentTimeMillis() { | |
return now; | |
} | |
/** | |
* Start automatic ticking. This will tick the clock, and update its current | |
* time value, about every 10 milliseconds. Note that this does not guarantee | |
* that the clock will get a distinctively new time value every 10 | |
* milliseconds. The clock can be stopped again at any time with the | |
* {@link #stop()} method. Starting an already started clock has no effect. | |
*/ | |
public static void start() { | |
tick(); | |
ticker.stopFlag = false; | |
if (ticker.getState() == Thread.State.NEW) { | |
ticker.start(); | |
} else { | |
LockSupport.unpark(ticker); | |
} | |
} | |
/** | |
* Stop automatic ticking. It can be resumed again with the {@link #start()} | |
* method. Stopping an already stopped clock has no effect. | |
*/ | |
public static void stop() { | |
ticker.stopFlag = true; | |
} | |
private static final class Ticker extends Thread { | |
public volatile boolean stopFlag; | |
public Ticker() { | |
super("Clock-Thread"); | |
setDaemon(true); | |
} | |
@Override | |
public void run() { | |
for (;;) { | |
if (stopFlag) { | |
LockSupport.park(); | |
} | |
tick(); | |
LockSupport.parkNanos(10000); // 10 millis | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment