2012-02-08 22 views
10

Ho bisogno di creare un timestamp (in millisecondi) in Java che è garantito essere univoco in quella particolare istanza VM. Cioè è necessario un modo per limitare il throughput di System.currentTimeMillis() in modo che restituisca al massimo un risultato ogni ms. Qualche idea su come implementarlo?Creazione di un timestamp univoco in Java

+2

non sono sicuro di quello che vuoi dire * * limitazione currentTimeMillis() in modo che restituisca al massimo * * un risultato ev ery ms? Se desideri timestamp univoci, preferiresti garantire che restituisca un valore diverso ad ogni chiamata, giusto? –

+0

Devono essere monotonicamente in aumento? Devono sopportare qualche relazione con il tempo * effettivo *? Devono essere univoci su più percorsi? –

risposta

30

Questo darà un tempo il più vicino possibile al tempo corrente senza duplicati.

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; 
    } 
} 

Un modo per evitare la limitazione di un id al milli-secondo è quello di utilizzare un micro-secondo timestamp. cioè moltiplicare currentTimeMS per 1000. Ciò consentirà 1000 id per millisecondo.

Nota: se il tempo scorre indietro, ad es. A causa di una correzione NTP, il tempo progredisce a 1 milli-secondo per invocazione fino a quando il tempo non si avvicina. ;)

+0

Grazie! Esattamente quello di cui avevo bisogno! – Yrlec

+0

Se usato correttamente, ciò significa che avrete ID univoci anche dopo aver riavviato l'applicazione. –

+1

Sembra buono! Cosa significa "usato correttamente" più precisamente? – Yrlec

1

È possibile utilizzare System.nanoTime(), che è il timer di sistema disponibile più preciso e dividerlo per milione per ottenere i millisecondi. Anche se non ci sono garanzie formali sulla frequenza con cui viene aggiornato, credo sia ragionevole presumere che aggiorni molto più (ordine/i di grandezza) frequentemente di una volta al millisecondo. Naturalmente, se crei timestamp interi di un intervallo inferiore a millisecondi, non possono essere tutti univoci.

Si noti che il valore assoluto nanoTime() è arbitrario. Se si desidera il tempo assoluto, calibrarlo in qualche modo, cioè confrontarlo con currentTimeMillis() all'avvio.

4

È possibile utilizzare System.nanoTime() per una migliore precisione

Anche se ho provato qui sotto e ogni volta che si dà valori diversi, probabilmente non è garantito per essere unico per tutto il tempo.

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); 
    } 

Un altro modo è quello di utilizzare AtomicInteger/AtomicLong classi per numeri unici, se il tempo non è importante per voi e basta numero unico, questo probabilmente è una scelta btter.

+2

nanoTime è monotono, ma non sempre unico. Puoi ottenere molti duplicati. per esempio. su Red Hat & Centos 5.x la risoluzione è micro-secondi, quindi ottieni molti valori ripetuti. –

+0

Grazie per le informazioni. Ho indovinato che dipende dal sistema operativo e dalla macchina. – fmucar

+1

Puoi usare nanoTime con un controllo diverso. (Simile alla mia soluzione) Il nanoTime è il tempo di attività in meno di secondi su molti sistemi. –

1

Durante la ricerca di una soluzione mi sono imbattuto ULIB (Universally Unique lexicographically ordinabili Identifier) ​​ https://github.com/huxi/sulky/tree/master/sulky-ulid/

Non è una lunga, ma più corto quindi UUID.

A ULID:

  • è compatibile con UUID/GUID di 1.21e + 24 ULIDs unici al millisecondo (1,208,925,819,614,629,174,706,176 per l'esattezza)
  • lexicographically ordinabili
  • Canonicamente codificate come una stringa di 26 caratteri, in contrapposizione all'UUID 36 carattere
  • Utilizza base32 di Crockford per una migliore efficienza e leggibilità (5 bit per carattere)
  • caso insensitive
  • nessun carattere speciale (sicuro URL)