Создание уникальной метки времени в Java

Мне нужно создать временную метку (в миллисекундах) на Java, которая, как гарантируется, будет уникальной в этом конкретном экземпляре VM. То есть необходимо каким-то образом ограничить пропускную способность System.currentTimeMillis(), чтобы он возвращал не более одного результата каждые миллисекунды. Любые идеи о том, как реализовать это?

Ответ 1

Это даст время как можно ближе к текущему времени без дубликатов.

private static final AtomicLong LAST_TIME_MS = new AtomicLong();
public static long uniqueCurrentTimeMS() {
    long now = System.currentTimeMillis();
    while(true) {
        long lastTime = LAST_TIME_MS.get();
        if (lastTime >= now)
            now = lastTime+1;
        if (LAST_TIME_MS.compareAndSet(lastTime, now))
            return now;
    }
}

Один из способов избежать ограничения одного идентификатора за миллисекунду - использовать микросекундную метку времени. то есть умножить currentTimeMS на 1000. Это позволит 1000 идентификаторов за миллисекунду.

Примечание: если время идет назад, например, из-за коррекции NTP, время будет только прогрессировать с 1 миллисекундой за каждый вызов, пока не наступит время.;)

Ответ 2

Вы можете использовать System.nanoTime() для лучшей точности

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

public static void main(String[] args) {
        long time1 = System.nanoTime();
        long time2 = System.nanoTime();
        long time3 = System.nanoTime();
        System.out.println(time1);
        System.out.println(time2);
        System.out.println(time3);
    }

Другим способом является использование классов AtomicInteger/AtomicLong для уникальных чисел, если время для вас не важно, и вам просто нужен уникальный номер, это, вероятно, выбор btter.

Ответ 3

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

Обратите внимание, что абсолютное значение nanoTime() произвольно. Если вы хотите абсолютное время, откалибруйте его каким-либо образом, то есть сравните его с currentTimeMillis() при запуске.

Ответ 4

При поиске решения я столкнулся с ULIB (Универсально уникальный лексикографически сортируемый идентификатор) https://github.com/huxi/sulky/tree/master/sulky-ulid/

Это не длинный, но более короткий, чем UUID.

A ULID:

  • Совместим с UUID/GUID 1.21e + 24 уникальных ULID за миллисекунду (1 208 925 819 614 629 174 480 706 176, если быть точным).
  • Лексикографически сортируемый
  • Канонически закодировано как строка с 26 символами, в отличие от UIID с 36 символами
  • Использует базу Crockford base32 для повышения эффективности и удобочитаемости (5 бит на символ)
  • Нечувствительность к регистру
  • Никаких специальных символов (безопасный URL)

Ответ 5

Не могли бы вы использовать java.util.UUID и timestamp() и clockSequence()?

Method Summary
    int clockSequence() 
        The clock sequence value associated with this UUID.
    long timestamp() 
        The timestamp value associated with this UUID.

Подробнее здесь: http://docs.oracle.com/javase/1.5.0/docs/api/java/util/UUID.html