Elettracompany.com

Компьютерный справочник
7 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

System currenttimemillis java

Java System.nanoTime () против System.currentTimeMillis

Java предоставляет два метода для измерения времени, System.nanoTime () и System.currentTimeMillis (). Но какой из них следует использовать в каких условиях? И что более эффективно?

На первый взгляд может показаться, что следует использовать nanoTime (), поскольку он дает более точное значение времени (в нано секундах по сравнению с миллисекундами, которые возвращает другой метод). Но всегда ли эффективно на процессоре использовать nanoTime? Давайте посмотрим на плюсы и минусы использования обоих методов:

System.currentTimeMillis ()

Плюсы:

  1. Это потокобезопасно . Потоковая безопасность означает, что если этот метод вызывается между двумя или более различными потоками, он не будет возвращать ошибочные результаты.
  2. Всегда возвращает абсолютное время, прошедшее с начала эпохи (количество миллисекунд с 1 января 1970 г. 00:00).
  3. Потребляет меньше тактов для выполнения (около 5-6 тактовых процессоров).
  4. Дает более точное время, так как точка отсчета (эпоха) является фиксированной.

Минусы:

  1. Менее точно . Результат где-то между 1/1000-й / 15/1000-й секунды. На некоторых машинах разрешение даже меньше 50 мс и может снизиться только до 10 мс.
  2. Это может дать неправильные результаты, если пользователь изменяет системное время, делает скачок в секунду или происходят изменения в синхронизации NTP.

System.nanoTime ()

Плюсы:

  1. Очень точный Время возврата составляет около 1/1000000-й секунды.
  2. Разрешение намного выше, чем currentTimeMillis () .

Минусы:

  1. Отраженный результат не имеет фиксированной контрольной точки. Согласно документации Java,
  2. Менее точный . Этот метод обеспечивает точность наносекунды, но не обязательно точность наносекунды. Нет никаких гарантий относительно того, как часто меняются значения.
  3. В зависимости от системы может потребоваться более 100 циклов процессора.
  4. Не потокобезопасен . Может возвращать ошибочные результаты, если используется между несколькими потоками.

Давайте посмотрим на рабочий пример, чтобы сравнить результаты этих двух функций:

// Java-программа для иллюстрации
// разница между
// Java System.nanoTime ()
// и System.currentTimeMillis

public static void main(String[] args)

// Получить текущее системное время в

// и нано и миллисекунды до

long nano_startTime = System.nanoTime();

long millis_startTime = System.currentTimeMillis();

// Выполнить работу, время которой нужно измерить

// Получить текущее системное время в обоих

System currenttimemillis java

That will print a human readable time in your local timezone.

To understand exactly what System.currentTimeMills() returns we must first understand: what UTC is, what UNIX timestamps are and how they form a universal time keeping standard.

The current UTC date/time is . Your local time is

A UNIX timestamp, also known as Epoch Time or POSIX timestamp, is a representation of a moment defined as the time that has elapsed since a reference known as the UNIX epoch: 1970-01-01 00:00:00 UTC (what is UTC). Using Java as an example, System.currentTimeMillis() returns just that, a UNIX timestamp in milliseconds — UNIX timestamps will often be measured in seconds as well (but System.currentTimeMillis() will always be in milliseconds). Following is a table that unifies these concepts:

Note that System.currentTimeMillis() is based on the time of the system / machine it’s running on.

In conclusion, the UNIX timestamp is just a system / format for representing a moment in time.
Check out some other date / time systems.

The ‘snapshot’ above represents the same moment from 4 different perspectives: John’s timezone, Juliette’s timezone, UTC (Coordinated Universal Time) and milliseconds from the Unix epoch.

Java’s Calendar (and deprecated Date ) itself stores time as milliseconds since the Unix Epoch. This is great for many reasons. It happens not only in Java but in other programming languages as well. In my experience i found the perfect time-keeping architecture emerges naturally from this: the Unix Epoch is January 1st, 1970, midnight, UTC. Therefore if you choose to store time as milliseconds since the Unix Epoch you have a lot of benefits:

  • architecture clarity: server side works with UTC, client side shows the time through its local timezone
  • database simplicity: you store a number (milliseconds) rather than complex data structures like DateTimes
  • programming efficiency: in most programming languages you have date/time objects capable of taking milliseconds since Epoch when constructed (which allows for automatic conversion to client-side timezone)

Code & architecture become simpler and more flexible when using this approach, which is also sketched below:

Benchmarking & performance monitoring can be done by calculating time differences («deltas») between starting points and end points. For example you might want to test how differences in your implementation affect speed:

What might happen above is that the sorting for such a small array could be so fast that the duration shows up as zero. For this you can use the trick of repeating the method call multiple times so that you get more relevant durations & comparisons:

System.currentTimeMillis() offers precision to the millisecond but its accuracy still depends on the underlying machine. This is why, in some cases, it might happen that two subsequent calls can return the same number even if they are in fact more than 1ms apart. The same is true about nanoTime() : precision is down to the nanosecond but accuracy doesn’t follow, it still depends on the machine.

System.nanoTime() , however, returning nanoseconds, may arguably be better suited to measure deltas (although reportedly a nanoTime() call can be slower than a currentTimeMillis() call — my experiments contradict this: they seem to take exactly the same amount of time). nanoTime() ‘s disadvantage is it doesn’t have a fixed reference point like currentTimeMillis() has the Unix epoch. nanoTime() ‘s reference might change with a system/machine restart, so from the mentioned methods currentTimeMillis() is the one to use for time-keeping.

UTC stands for Coordinated Universal Time. GMT stands for Greenwich Mean Time. UTC is a universal time keeping standard by itself and a GMT successor. A time expressed in UTC is essentially the time on the whole planet. A time expressed in GMT is the time in the timezone of the Greenwich meridian. In current computer science problems (and probably most scientific ones) UTC and GMT expressed in absolute value happen to have identical values so they have been used interchangeably.

Читать еще:  Math atan2 java

A detailed analysis reveals that literature and history here are a bit ambiguous. UTC essentially appeared in 1960, GMT being the ‘main thing’ until then. Unlike GMT which is based on solar time and originally calculated a second as a fraction of the time it takes for the Earth to make a full rotation around its axis, UTC calculates a second as “the duration of 9192631770 periods of the radiation corresponding to the transition between the two hyperfine levels of the ground state of the cesium 133 atom”. UTC’s second is far more precise than GMT’s original second. In 1972 leap seconds were introduced to synchronize UTC time with solar time. These 2 turning points (different definition of a second and the introduction of leap seconds) ‘forced’ GMT to be the same as UTC based on what seemed a gradual, tacit convention. If you were to calculate true GMT today i would see it based on its original definition of 1 second = 1/86400 days and this would for sure return a different absolute value than what UTC gives us. From this point of view the name “GMT” seems deprecated, but kept around for backward compatibility, traditional timezone based representation of time and sometimes legal reasons.

Java Specialist

Блог о памяти, сборщике мусора, многопоточности и производительности в java

Содержание

понедельник, 16 апреля 2012 г.

Измерение времени и засыпание потоков

В данном топике я хотел бы поговорить об инструментарии доступном в java для измерения времени и запуска таймеров, об их точности, производительности и возможных проблемах при работе с ними. Например, на Windows при определенных паттернах работы с Thread.sleep() системные часы могут начать идти заметно быстрее, добавляя по несколько секунд на каждом часе. Так же можно столкнуться с большим джиттером при работе с таким классом как ScheduledThreadPoolExecutor .

System.currentTimeMillis()
System.nanoTime()

Второй метод использует специальные счетчики, не связанные с системными часами (хотя на некоторых платформах он и может быть реализован через них, но это скорее исключение нежели правило). Формально System.nanoTime() возвращает наносекунды, но последовательные вызовы этого метода вряд ли дадут точность больше микросекунд. На большинстве систем данный метод будет возвращать неубывающие значения, для чего ему может потребоваться внутренняя синхронизация, если он будет вызываться на разных процессорах. Поэтому производительность этого метода очень сильно зависит от железа, и на некоторых машинах запрос к этому методу может легко занимать больше времени, чем запрос к System.currentTimeMillis() [2].

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

Thread.sleep() / Object#wait()

С помощью данных методов можно попросить текущий поток уснуть на определенное количество миллисекунд. Точность просыпания будет зависеть от размера интервала прерываний на вашей ОС. На Windows это обычно 10 мс (но на некотором железе может быть и 15 мс [4]). Однако длина этого интервала может быть изменена даже стандартными средствами java. Данное переключение происходит автоматически, если вы просите заснуть любой поток на время не кратное, текущему интервалу прерываний. Причем, когда данный поток проснется, ОС вернется обратно к штатному режиму.

Однако с этим надо быть очень аккуратным, так как частое переключение между данными режимами из-за бага в Windows [6] может вызвать изменение в нормальном ходе системных часов. Я однажды столкнулся с жалобами клиентов одного из приложений над которыми я работал, что когда они запускают наш продукт, то их часы начинают спешить на несколько секунд в час. Особо никто не обращал на эти жалобы внимание, так как не особо понимали как это вообще может происходить. Как оказалось, такое действительно может иметь место, если Windows часто переключается между режимами с разной точностью интервалов прерывания. Сделать это довольно просто, достаточно запустить в фоне какой-нибудь поток, который в цикле будет вызывать Thread.sleep() , передавая в качестве параметра небольшое число не кратное 10 мс. Например, 1, 5 или 25. Самое забавное, что данное переключение произойдет даже если вы попросите поток уснуть на 1001 мс, что уже казалось бы бессмысленным, зато это дает очень изящный workaround, описанный ниже. Но стоит заметить, что при вызове sleep() на длительное время переключение режимов происходит не часто и проблема со спешкой системных часов проявляться не будет. Еще на javamex [5] пишут, что даже при дефолтном периоде прерываний в 15 мс, JVM считает, что дефолтное значение 10 и может перейти в режим повышенной точности прерываний при попытки засыпания на 15 мс.

Чтобы обойти баг со спешкой часов в JVM был сделан флаг -XX:+ForceTimeHighResolution , который должен был на старте JVM переводить систему в режим повышенной точности прерываний. Но из-за бага в его имплементации [3], получилось, что он делает совершенно другое, а именно замораживает штатную длину прерывания и никакие команды sleep() уже ее не поменяют. Что впрочем тоже явилось решением проблемы отклонения в ходе системных часов. Забавно, но официальный ответ на баг в реализации данного флага состоит в том, что его править не будут, так как, во-первых, он решает изначальную проблему, во-вторых он был внедрен очень давно и многие уже рассчитывают на то, как он работает сейчас, и, в-третьих, существует изящный workaround, который позволяет сделать именно то, для чего изначально задумался этот флаг.

Читать еще:  Java lang stackoverflowerror null

Система.currentTimeMillis против системы.nanoTime

Точность Против Точности

что я хотел бы знать, Следует ли мне использовать

10 ответов:

если вы просто ищете чрезвычайно точные измерения времени используйте System.nanoTime() . System.currentTimeMillis() даст вам наиболее точное возможное затраченное время в миллисекундах с момента эпохи, но System.nanoTime() дает вам наносекундное точное время относительно некоторой произвольной точки.

из документации Java:

возвращает текущее значение наиболее точного доступного системного таймера в наносекундах.

этот метод может быть использован только для измерьте затраченное время и нет связанные с любым другим понятием системы или настенные часы. Возвращаемое значение представляет наносекунды, так как некоторые фиксированное, но произвольное время (возможно, в будущее, поэтому ценности могут быть негативный.) Этот метод обеспечивает наносекундная точность, но не обязательно наносекундная точность. Нет гарантии сделаны о том, как часто значения меняются. Различия в последовательных вызовах, которые охватывают больше чем примерно 292 года (2 63 наносекунды) не будет точно вычислить затраченное время из-за численного переполнение.

например, для измерения времени выполнения некоторого кода:

Потокобезопасность

поскольку никто больше не упоминал об этом.

Не Безопасно

это не безопасно сравнивать результаты System.nanoTime() вызовы между различными потоками. Даже если события потоков происходят в предсказуемом порядке, разница в наносекундах может быть положительной или отрицательной.

безопасное

System.currentTimeMillis() безопасно для использования между потоками.

обновление Аркадий: Я наблюдал более правильное поведение System.currentTimeMillis() на Windows 7 в Oracle Java 8. Время было возвращено с точностью до 1 миллисекунды. Исходный код в OpenJDK не изменился, поэтому я не знаю, что вызывает лучшее поведение.

Дэвид Холмс из Sun опубликовал статью в блоге пару лет назад, в которой очень подробно рассматривается API синхронизации Java (в частности System.currentTimeMillis() и System.nanoTime() ), когда вы хотели бы использовать, какие и как они работать внутренне.

один очень интересный аспект таймера, используемого Java на Windows для API, которые имеют параметр timed wait, заключается в том, что разрешение таймера может изменяться в зависимости от того, какие другие вызовы API могут быть сделаны — в масштабах всей системы (а не только в конкретном процессе). Он показывает пример, где с помощью Thread.sleep() вызовет это изменение разрешения.

System.nanoTime() не поддерживается в старых JVMs. Если это вызывает беспокойство, придерживайтесь currentTimeMillis

что касается точности, вы почти правильно. На некоторых машинах Windows, currentTimeMillis() имеет разрешение около 10 мс (не 50 мс). Я не уверен, почему, но некоторые машины Windows так же точны, как и машины Linux.

я использовал GAGETimer в прошлом со скромным успехом.

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

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

Если вы хотите использовать тактовое время, но избежать разрывов из-за синхронизации времени в интернете, вы можете рассмотреть клиент NTP, такой как Meinberg, который «настраивает» тактовую частоту до нуля, а не просто периодически сбрасывает часы.

Я говорю Из личного опыта. В погодном приложении, которое я разработал, я получал случайные всплески скорости ветра. Потребовалось время для меня, чтобы поймите, что моя временная база была нарушена поведением времени часов на типичном ПК. Все мои проблемы исчезли, когда я начал использовать nanoTime. Последовательность (монотонность) была более важна для моего приложения, чем необработанная точность или абсолютная точность.

да, если такая точность требуется использовать System.nanoTime() , но имейте в виду, что вам тогда требуется Java 5+ JVM.

в моих системах XP я вижу, что системное время сообщается по крайней мере 100 микросекунд 278 наносекунд использовать следующий код:

У меня был хороший опыт работы с nanotime. Он обеспечивает время настенных часов в виде двух долгих (секунд с момента эпохи и наносекунд в течение этой секунды), используя библиотеку JNI. Он доступен с частью JNI, предварительно скомпилированной как для Windows, так и для Linux.

для обновления игровой графики и плавного положения используйте System.nanoTime() , а не System.currentTimeMillis() . Я переключился с currentTimeMillis() на nanoTime () в игре и получил значительное визуальное улучшение плавности движения.

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

  • точное позиционирование пикселя ниже разрешения настенных часов
  • возможность анти-псевдонима между пикселями, если ты хочешь
  • неточность настенных часов Windows
  • дрожание часов (непоследовательность, когда настенные часы фактически тикают вперед)

как показывают другие ответы, nanoTime имеет стоимость производительности при повторном вызове — было бы лучше вызвать его только один раз за кадр и использовать одно и то же значение для расчета всего кадра.

System.currentTimeMillis() не является безопасным для истекшего времени, потому что этот метод чувствителен к изменениям часов системы в реальном времени системы. Вы должны использовать System.nanoTime . Пожалуйста, обратитесь к системной справке Java:

о методе nanoTime:

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

Читать еще:  Javascript заполнение таблицы

Переопределить Систему Java.currentTimeMillis для тестирования чувствительных кода

есть ли способ, либо в коде, либо с аргументами JVM, переопределить текущее время, как представлено через System.currentTimeMillis , кроме ручного изменения системных часов на главной машине?

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

к сожалению, многие устаревший код вызывает такие функции, как new Date() или Calendar.getInstance() , оба из которых в конечном итоге призыв к System.currentTimeMillis .

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

Итак, мой вопрос:

есть ли способ переопределить то, что возвращается System.currentTimeMillis ? Например, чтобы сказать JVM автоматически добавлять или вычитать некоторое смещение перед возвращением из этого метода?

12 ответов

Я сильно рекомендую вместо того, чтобы возиться с системными часами, вы стиснуть зубы и рефакторинг устаревшего кода, которые использовать сменные часы. в идеале это должно быть сделано с инъекцией зависимостей, но даже если вы использовали сменный синглтон, вы получите тестируемость.

это может быть почти автоматизировано с поиском и заменой для версии singleton:

  • заменить Calendar.getInstance() с Clock.getInstance().getCalendarInstance() .
  • заменить new Date() С Clock.getInstance().newDate()
  • заменить System.currentTimeMillis() С Clock.getInstance().currentTimeMillis()

(etc по мере необходимости)

как только вы сделали этот первый шаг, вы можете заменить синглтон на DI немного за раз.

tl; dr

есть ли способ, либо в коде, либо с аргументами JVM, переопределить текущее время, как представлено через систему.currentTimeMillis, кроме ручного изменения системных часов на главной машине?

Clock на java.время

у нас есть новое решение проблемы замены подключаемых часов для облегчения тестирования с помощью faux значения даты и времени. Этот java.пакет времени на Java 8 включает абстрактный класс java.time.Clock , с явной целью:

разрешить альтернативные часы, которые будут подключены по мере необходимости

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

изменен каденции

различные tick… методы производят часы, которые увеличивают текущий момент с другой каденцией.

по умолчанию Clock сообщает время обновляется так часто, как МС в Java 8 и в Java 9 так же хорошо, как наносекунд (в зависимости от вашего оборудования). Вы можете попросить, чтобы истинный текущий момент был сообщен с другим зернистость.

  • tickSeconds — инкременты в целых секундах
  • tickMinutes — инкременты в целых минутах
  • tick — инкременты по пройденному Duration , теперьрежим обслуживания, советует миграцию в java.время классы.

чтобы узнать больше, см. В Oracle Учебник. И search Stack Overflow для многих примеров и объяснений. Спецификация JSR 310.

вы можете обменять java.время объекты непосредственно с вашей базой данных. Используйте драйвер JDBC соответствуют JDBC 4.2 или позже. Нет необходимости в строках, нет необходимости в java.sql.* классы.

где получить java.время занятий?

  • Java SE 8, Java SE 9, и позже
    • встроенный.
    • часть стандартного API Java с комплексная реализация.
    • Java 9 добавляет некоторые незначительные функции и исправления.
  • Java SE 6 и Java SE 7
    • большая часть java.функциональность времени обратно портирована на Java 6 & 7 в ThreeTen-Backport.
  • Android
    • более поздние версии Android bundle реализации java.классы время.
    • для более раннего Android (ThreeTenABP проект приспосабливается ThreeTen-Backport (упоминалось выше). См.как использовать ThreeTenABP..

на ThreeTen-Extra проект расширяет java.время с дополнительными занятиями. Этот проект является испытательной площадкой для возможных будущих дополнений к java.время. Здесь вы можете найти полезные классы, такие как Interval , YearWeek , YearQuarter и больше.

«использовать время Joda» почти всегда лучший ответ на любой вопрос, связанный с «как достичь X с java.утиль.Дата / Календарь?»

Итак, здесь идет (предполагая, что вы только что заменили все свои new Date() С new DateTime().toDate() )

Если вы хотите импортировать библиотеку с интерфейсом (см. комментарий Джона ниже), вы можете просто использовать Prevayler это!—5—>, который обеспечит реализации, а также стандартный интерфейс. Полная банка составляет всего 96 КБ, поэтому она не должна ломать банк.

хотя использование некоторого шаблона DateFactory кажется приятным, он не охватывает библиотеки, которые вы не можете контролировать — представьте себе аннотацию проверки @Past с реализацией, полагающейся на систему.currentTimeMillis (есть такой).

вот почему мы используем jmockit, чтобы издеваться над системным временем напрямую:

потому что невозможно добраться до исходного размонтированного значения millis, мы используем nano timer вместо этого — это не связано с настенными часами, но относительного времени достаточно здесь:

есть документированная проблема, что с HotSpot время возвращается к норме после ряда вызовов-вот отчет о проблеме:http://code.google.com/p/jmockit/issues/detail?id=43

чтобы преодолеть это, мы должны включить одну конкретную оптимизацию точки доступа-запустите JVM с этим аргументом -XX:-Inline .

пока это не может быть совершенно для продукции, как раз отлично для тестов и совершенно прозрачно для применения, особенно когда DataFactory не имеет бизнес-смысла и вводится только из-за тестов. Было бы неплохо иметь встроенную опцию JVM для запуска в разное время, жаль, что это невозможно без таких хаков.

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

EDIT июль 2014: JMockit сильно изменился в последнее время, и вы обязаны использовать jmockit 1.0 для правильного использования (IIRC). Определенно не может обновиться до новейшей версии, где интерфейс полностью отличается. Я думал о том, чтобы вложить все необходимое. но так как эта штука нам не нужна в наших новых проектах, я ее вообще не разрабатываю.

0 0 голоса
Рейтинг статьи
Ссылка на основную публикацию
ВсеИнструменты 220 Вольт