Serhii
2 min readJul 1, 2018

--

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

А вы знали, что на ваших серверах есть по сути два вида часов? Часы показывающие истинное время и монотонные часы. Первые часы показывают абсолютное время. Например, в UNIX-системах это количество (мили)секунд прошедших с 1 января 1970 года, оно же unixtime. Так же известно, что эти часы полагаются на hardware-часы самого компьютера, могут идти немного вразнобой и для синхронизации часов используются службы типа NTP, которые синхронизируют часы сервера со сторонними серверами, время на которых принимается как заведомо точное. Зачем же нужны вторые?

Приведем пример из Java. Здесь истинное время можно получить с помощью вызова функции System.currentTimeMillis()

Представим, что нам нужно измерить время выполнения какого-нить куска кода. Делается это примерно так:

Long t1 = System.currentTimeMillis();// здесь испоняется наш кодLong t2 = System.currentTimeMillis() — t1;

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

Long t1 = System.currentTimeMillis(); // Системное время — 1530483376000// здесь испоняется наш код, допустим 2 секунды// синхронизация часов, оказалось, что наши часы спешат на 3 секунды, системное время откатили на три секунды назадLong t2 = System.currentTimeMillis() — t1; // Системное время — 1530483375000

В таком случае t2 будет равно t1 + 2 секунды прошедшего времени - 3 секунды поправки = -1 секунда.

Наш код настолько быстр, что выполняется -1000 милисекунд? Океей.

Поэтому и нужны монотонные часы(monotonic clock). В джаве значение монотонных часов можно получить с помощью вызова функции System.nanoTime()

Само по себе значение, возвращаемое этой функцией, не несет никакого смысла. Это может быть банально количество наносекунд со времени старта системы или что-то в таком духе. Важно лишь то, что разница между двумя вызовами монотонных часов всегда будет отображать прошедшее между этими вызовами время. Эти значения сами по себе могут быть даже отрицательными. Важно лишь то, что в примере:

Long t1 = System.nanoTime();// здесь испоняется наш кодLong t2 = System.nanoTime() — t1;

t2 будет равно времени исполнения кода, вне зависимости от того, как менялось системное время. Можете даже провести эксперимент типа:

Long t1 = System.nanoTime();Thread.sleep(20000); // ждем 20 секунд// переводим системные часы на час назад или впередLong t2 = System.nanoTime() — t1;// t2 все равно будет примерно равен 20 секундам

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

--

--