Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there any consistent (monotonic) Clock implementation in Java?

The default java.time.Clock implementation is based on System.currentTimeMillis(). As discussed for example here, Monotonically increasing time in Java?, it is not guaranteed to be monotonic.

And indeed, I regularly experience a situation, where the system time is automatically adjusted a few seconds to the past, and the java clock jumps back too.

//now() returns 2016-01-13T22:34:05.681Z
order.setCreationTime(Instant.now());

//... something happens, order gets cancelled

//now() returns 2016-01-13T22:34:03.123Z
//which is a few seconds before the former one,
//even though the call was performed later - in any reasonable sense.
//The recorded history of events is obviously inconsistent with the real world.
order.setCancelationTime(Instant.now());

It is then impossible to perform time-sensitive things, like recording and analysing event history, when one can not rely on time going only in one direction.

The aforementioned post says that System.nanoTime() is monotonic (if the underlying system supports it). So, if I want to base my code on the java.time API, I would need Clock that uses nanoTime internally to ensure one-way flow of the time. Maybe something like this would work. Or would't it?

public class MyClock() extends java.time.Clock {

    private final long adjustment;

    public MyClock() {
        long cpuTimeMillis = System.nanoTime()/1000000;
        long systemTimeMillis = System.currentTimeMillis();
        adjustment = systemTimeMillis - cpuTimeMillis;
    }

    @Override
    public long millis() {
        long currentCpuTimeMillis = System.nanoTime()/1000000;
        return currentCpuTimeMillis + adjustment;
    }
}   

It is just a sketch, not a full Clock implementation. And I suppose a proper implementation should also perform the adjustment against another Clock passed in the constructor, rather than directly against the currentTimeMillis().

Or, is there already such a monotonic Clock implementation available anywhere? I would guess there must have been many people facing the same issue.

Conclusion

Thanks for the inspiring comments and answers. There are several interesting points scattered across the comments, so I will summarize it here.

1. Monotonic clock

As for my original question, yes, it is possible to have monotonic clock that is not affected by system time jumping backwards. Such implementation can be based on System.nanoTime() as I suggested above. There used to be problems with this aproach in the past, but it should work fine on today's modern systems. This approach is already implemented for example in the Time4J library, their monotonic clock can be easily converted to java.time.Clock:

Clock clock = TemporalType.CLOCK.from(SystemClock.MONOTONIC);

2. Proper system time control

It it possible to configure system time management (ntpd in unix/linux), so that the system time virtually never moves back (it gets just slowed down if necessary), then one can rely on the system time being monotonic, and no clock-magic is necessary in Java.

I will go this way, as my app is server-side and I can get the time under control. Actually, I experienced the anomalies in an experimental environment that I installed myself (with only superficial knowledge of the domain), and it was using just ntpdate client (which can jump backwards if the time is out of sync), rather than ntpd (which can be configured so that it does not jump back).

3. Using sequences rather than clock

When one needs to track a strong relation what happened before what, it is safer to give the events serial numbers from an atomically generated sequence and not rely on the wall clock. It becomes the only option once the application is running on several nodes (which is not my case though).

like image 862
Jan X Marek Avatar asked Jan 13 '16 23:01

Jan X Marek


People also ask

Is nanoTime monotonic?

In comparison, System. nanoTime() is monotonic so we should have used this one.

What is monotonic timestamp?

Unlike a UTC timestamp (which starts January 1st, 1970), Monotonic time starts at an arbitrary point. It cannot move backwards. Finally, and most importantly, it is completely independent of the system clock: changes to the system clock will not affect a monotonic time.

How fast is currentTimeMillis?

System. currentTimeMillis() takes about 29 nanoseconds per call while System.


Video Answer


2 Answers

As @the8472 says, the key is to have the time synchronization on the machine (where the jvm runs) correct.

If you program a client then it really can be dangerous to rely on the system clocks. But for servers, there is a solution - you might want to consider using NTP with strict configuration.

In here they basicly explain that NTP will slow down the time and not set it backwards.

And this NTP documentation says :

Sometimes, in particular when ntpd is first started, the error might exceed 128 ms. This may on occasion cause the clock to be set backwards if the local clock time is more than 128 s in the future relative to the server. In some applications, this behavior may be unacceptable. If the -x option is included on the command line, the clock will never be stepped and only slew corrections will be used.

like image 158
Milos Gregor Avatar answered Oct 26 '22 02:10

Milos Gregor


Do note that nanoTime may increase monotonically but it does not relate nicely to wall time, e.g. due to hibernation events, VM suspension and similar things.

And if you start distributing things across multiple servers then synchronizing on currentMillis may also bite you again due to clock drift.

Maybe you should consider getting the system time of your servers under control.

Or track relative sequence of the events separately from the time at which they were supposedly recorded.

like image 41
the8472 Avatar answered Oct 26 '22 01:10

the8472