https://leetcode.com/discuss/interview-question/350166/google-onsite-timer
Given the following class with 2 methods
class MySystem {
/**
* Waits durationMillis milliseconds then runs the callback.
*
* Only one timer can be pending at one time. If called again before the
* duration expires, the original timer is overwritten without running
* callback.
*/
static void setTimer(long durationMillis, Runnable callback);
/** Returns the current time in milliseconds since system boot. */
static long getCurrentTimeMillis();
}
Use these methods to implement the 3rd method to support multiple timers:
/**
* Waits durationMillis milliseconds then runs the callback.
*
* Supports multiple concurrent timers. Calling addTimer will not break
* any previously started timers.
*/
void addTimer(long durationMillis, Runnable callback);
Usage is as follows:
MySystem sys = new MySystem();
sys.addTimer(100, runnable1);
Thread.sleep(50);
sys.addTimer(100, runnable2);
You can use a priority queue to keep all the timers with minimum time. You can maintain your own Runnable which will get's triggered when the timer goes off. At that time you can pop the next time and call the setTime api. NOTE : You need to subtract the time you have already elapsed when you trigger next alarm.
interface MySystem {
void setTimer(long durationMillis, Runnable callback);
long getCurrentTimeMillis();
void addTimer(long durationMillis, Runnable callback);
}
abstract class AbstractMySystem implements MySystem {
private final NavigableMap<Long, List<Runnable>>
callbacks = new TreeMap<>();
@Override
public void addTimer(long durationMillis, Runnable callback) {
synchronized (callbacks) {
assert durationMillis >= 0;
long scheduledTime = getCurrentTimeMillis() + durationMillis;
callbacks.computeIfAbsent(scheduledTime, t -> new ArrayList<>()).add(callback);
reschedule();
}
}
private void reschedule() {
synchronized (callbacks) {
final Long next = callbacks.firstKey();
if (next != null) {
setTimer(Math.max(0, next - getCurrentTimeMillis()), () -> {
synchronized (callbacks) {
for (Runnable runnable : callbacks.get(next)) {
setTimer(0, runnable);
}
callbacks.remove(next);
reschedule();
}
});
}
}
}
}