Будет ли System.currentTimeMillis всегда возвращать значение >= предыдущие вызовы?

http://java.sun.com/j2se/1.4.2/docs/api/java/lang/System.html#currentTimeMillis() говорит:

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

Мне не ясно, гарантирован ли, что этот код всегда будет печатать все увеличивающиеся (или одинаковые) номера.

while (1) { 
    System.out.println(System.currentTimeMillis() );
}

Ответ 1

Короткий ответ - нет, System.currentTimeMillis() не является монотонным. Он основан на системном времени и, следовательно, может быть изменен в любом случае (вперед или назад) в случае регулировки часов (например, через NTP).

System.nanoTime() является монотонным, тогда и только тогда, когда базовая платформа поддерживает CLOCK_MONOTONIC - см. комментарии к отчет об ошибке Java 6458294 для хорошая запись при некоторых обстоятельствах, когда это/неверно.

(И, как дополнительный анекдот, я лично наблюдал (несколько раз) System.currentTimeMillis() запустил "назад", в отсутствие регулировки часов, по потокам - то есть, вызов этого метода в один поток вернулся более низкое значение, чем вызов в другом потоке, даже если он произошел в хронологическом порядке после него в режиме реального времени)

Если вам нужен монотонный источник, System.nanoTime() на платформе, поддерживающей монотонность, является вашим лучшим вариантом.

Ответ 2

Нет, это не всегда будет >= все предыдущие вызовы.

  • Он может не увеличиваться каждый раз, если вы вызываете его несколько раз подряд из одного потока (я знаю, что это = часть > =, но поведение часто удивляет людей).

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

  • Наиболее серьезно, значение может вернуться во времени на большую сумму, если пользователь (редкий) или NTP-синхронизация (потенциально общий) настраивает системные часы.

Ответ 3

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

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

Ответ 4

Если вы хотите монотонно увеличить значение, вы можете сделать что-то вроде.

public enum Time {
    ;
    private static long lastTime;
    public synchronized static long increasingTimeMillis() {
        long now = System.currentTimeMillis();
        if (now > lastTime)
            return lastTime = now;
        return ++lastTime;
    }
}

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

Ответ 5

@Марк Рушаков прав; nanoTime() может быть немного более надежным.

Добавление: обратите внимание на предостережения, процитированные @Steven Schlansker.