public classTimeflakeId {private final static int SEQUENCE_MASK = 999;private final RecyclableAtomicInteger atomic = newRecyclableAtomicInteger();private long lastTimestamp = -1L;private long lastTsFormatted = -1L;public longnextId() {long timestamp =millisecond();if (timestamp
String.format("Wait for %d milliseconds", lastTimestamp -timestamp));
}if (lastTimestamp ==timestamp) {int sequence =atomic.incrementAndRecycle(SEQUENCE_MASK);if (sequence == 0) {
timestamp=waitTilNextMillis(lastTimestamp);
lastTimestamp=timestamp;
lastTsFormatted=getFormattedTimestamp();
}return lastTsFormatted * 1000 +sequence;
}else{
atomic.set(0);
lastTimestamp=timestamp;
lastTsFormatted=getFormattedTimestamp();return lastTsFormatted * 1000;
}
}private long waitTilNextMillis(final longlastTimestamp) {longtimestamp;for(;;) {
timestamp= this.millisecond();if (timestamp >lastTimestamp) {returntimestamp;
}
}
}private longmillisecond() {returnSystem.currentTimeMillis();
}public static final int EPOCH_YEAR = 1970;public static final long[][] MONTH_DAYS ={
{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};public static final long MSECS_DAY = 1000*3600*24L;private longgetFormattedTimestamp() {long ts = lastTimestamp + 1000L*3600*8;long dayclock = (ts % MSECS_DAY) / 1000L;long dayno = ts /MSECS_DAY;long mil = ts % 1000L;long sec = dayclock % 60;long min = (dayclock % 3600) / 60;long hour = dayclock / 3600;long year = 0;while (dayno >= yearDays(EPOCH_YEAR +year)) {
dayno-= yearDays(EPOCH_YEAR +year);
year++;
}long[] monthDays = leapYear(EPOCH_YEAR + year) ? MONTH_DAYS[1] : MONTH_DAYS[0];int mon = 0;while (dayno >=monthDays[mon]) {
dayno-=monthDays[mon];
mon++;
}
mon++;long mday = dayno + 1;return ((year > 30)? year - 30 : year + 70) * 10000000000000L
+ mon * 100000000000L
+ mday * 1000000000L
+ hour * 10000000L
+ min * 100000L
+ sec * 1000L
+mil;
}private static int yearDays(longyear) {return leapYear(year) ? 366 : 365;
}private static boolean leapYear(longyear) {return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
}public static voidmain(String[] args) {
TimeflakeId worker= newTimeflakeId();long start =System.currentTimeMillis();int total = 50000;for (int i = 0; i < total; i ++) {//System.out.println(worker.nextId());
worker.nextId();
}long duration = System.currentTimeMillis() -start;
System.out.println("Total: " + duration + "ms, " + total/duration + "/ms");
}
}