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;
}
}
1ミリ秒あたり1つのIDの制限を回避する1つの方法は、マイクロ秒のタイムスタンプを使用することです。つまり、currentTimeMSに1000を掛けます。これにより、1ミリ秒あたり1000のIDが許可されます。
注:たとえばNTP修正のために時間が逆行した場合、時間は追いつくまで、呼び出しごとに1ミリ秒で進行します。;)
精度を高めるために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);
}
もう1つの方法は、時間が重要ではなく、一意の番号が必要な場合は、一意の番号にAtomicInteger
/AtomicLong
クラスを使用することです。これは、おそらくより適切な選択です。
解決策を探しているときに、[〜#〜] ulib [〜#〜](Universally Unique Lexicographically Sortable Identifier)https://github.com/huxi/sulky/tree/master/sulky-ulid/
長くはありませんが、UUIDよりも短くなっています。
ULID:
利用可能な最も正確なシステムタイマーであるSystem.nanoTime()
を使用し、それを100万で割ってミリ秒を取得できます。更新の頻度について正式な保証はありませんが、1ミリ秒に1回よりもはるかに頻繁に(大きさのオーダーで)更新されると想定するのが妥当だと思います。もちろん、ミリ秒未満の間隔で整数のタイムスタンプを作成する場合、それらすべてを一意にすることはできません。
絶対値nanoTime()
は任意であることに注意してください。絶対時間を必要とする場合は、なんらかの方法で調整します。つまり、開始時にcurrentTimeMillis()
と比較します。
_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