Создание уникальной метки времени в Java - PullRequest
13 голосов
/ 08 февраля 2012

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

Ответы [ 5 ]

37 голосов
/ 08 февраля 2012

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

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 миллисекунда за вызов до тех пор, пока время не настанет. ;)

4 голосов
/ 08 февраля 2012

Вы можете использовать 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 классы для уникальных номеров, если время не важно для вас, и вам просто нужен уникальный номер, это, вероятно, лучший выбор.

2 голосов
/ 22 декабря 2017

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

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

ULID:

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

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

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

0 голосов
/ 08 февраля 2012

Не могли бы вы, возможно, использовать 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

...