Подтвердить что ты не робот

Есть ли последовательная (монотонная) реализация часов в Java?

По умолчанию реализация java.time.Clock основана на System.currentTimeMillis(). Как обсуждалось здесь, например, Монотонное увеличение времени на Java?, не гарантируется монотонность.

И действительно, я регулярно испытываю ситуацию, когда системное время автоматически корректируется на несколько секунд в прошлое, а часы java тоже возвращаются.

//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());

Затем невозможно выполнять зависящие от времени вещи, такие как запись и анализ истории событий, когда нельзя полагаться на время только в одном направлении.

В вышеприведенном сообщении говорится, что System.nanoTime() является монотонным (если базовая система его поддерживает). Поэтому, если я хочу использовать свой код в API java.time, мне понадобится Clock, который использует nanoTime для обеспечения одностороннего потока времени. Может быть, что-то вроде этого будет работать. Или это не так?

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;
    }
}   

Это всего лишь эскиз, а не полная реализация часов. И я полагаю, что правильная реализация также должна выполнять настройку против другого Clock, переданного в конструкторе, а не непосредственно против currentTimeMillis().

Или, существует ли такая монотонная реализация Clock в любом месте? Я бы предположил, что, должно быть, было много людей, столкнувшихся с одной и той же проблемой.

Заключение

Спасибо за вдохновляющие комментарии и ответы. Есть несколько интересных моментов, разбросанных по комментариям, поэтому я опишу их здесь.

1. Монотонные часы

Что касается моего первоначального вопроса, да, можно иметь монотонные часы, на которые не влияет системное время, отбрасывающее назад. Такая реализация может быть основана на System.nanoTime(), как я предложил выше. Раньше были проблемы с этим aproach в прошлом, но на современных современных системах он должен хорошо работать. Этот подход уже реализован, например, в библиотеке Time4J, их монотонные часы могут быть легко преобразованы в java.time.Clock:

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

2. Правильное системное управление временем

Можно настроить системное управление временем (ntpd в unix/linux), так что системное время практически никогда не возвращается (при необходимости оно просто замедляется), тогда можно полагаться на то, что время системы монотонно и в Java нет часового магии.

Я пойду так, потому что мое приложение является серверным, и я могу контролировать время. Фактически, я испытал аномалии в экспериментальной среде, в которой я установил себя (только с поверхностным знанием домена), и использовал только клиент ntpdate (который может перепрыгнуть назад, если время не синхронизировано), а не ntpd (что может быть сконфигурирован так, чтобы он не возвращался назад).

3. Использование последовательностей, а не часов

Когда нужно отслеживать сильное отношение, что было до этого, безопаснее давать серийные номера событий из атомарно генерируемой последовательности и не полагаться на настенные часы. Он становится единственным вариантом, когда приложение работает на нескольких узлах (это не мое дело, хотя).

4b9b3361

Ответ 1

Как поясняет @the8472, ключ должен синхронизировать синхронизацию времени на машине (где работает jvm).

Если вы программируете клиент, тогда действительно опасно полагаться на системные часы. Но для серверов есть решение - вы можете рассмотреть возможность использования NTP со строгой конфигурацией.

Здесь они в основном объясняют, что NTP замедлит и не установите его назад.

И эта документация NTP говорит:

Иногда, в частности, когда ntpd сначала запускается, ошибка может превышает 128 мс. Иногда это может привести к тому, что часы будут установлены назад, если местное время часов составляет более 128 с в будущем относительно сервера. В некоторых приложениях это поведение может быть неприемлемо. Если в командной строке включена опция -x, часы никогда не будут ступенчатыми, и будут использоваться только исправленные поправки.

Ответ 2

Обратите внимание, что nanoTime может увеличиваться монотонно, но оно не очень хорошо относится к времени на стене, например. из-за событий гибернации, подвески VM и т.д.

И если вы начнете распространять вещи на нескольких серверах, тогда синхронизация на currentMillis может снова укусить вас.

Возможно, вам стоит подумать о том, как контролировать системное время на ваших серверах.

Или отслеживать относительную последовательность событий отдельно от времени, в которое они якобы были записаны.