package net.xnzn.utils; import com.google.common.base.Preconditions; import java.time.LocalDateTime; import java.time.ZoneId; public class Id { private static final long EPOCH = LocalDateTime.of(2021, 12, 29, 9, 2).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(); private static final long SEQUENCE_BITS = 12L; private static final long WORKER_ID_BITS = 10L; static final long WORKER_ID_MAX_VALUE = 1024L; private static final long SEQUENCE_MASK = 4095L; private static final long WORKER_ID_LEFT_SHIFT_BITS = 12L; private static final long TIMESTAMP_LEFT_SHIFT_BITS = 22L; static Long WORKER_ID; private static long SEQUENCE; private static long LAST_TIME; public Id(Long workerId) { WORKER_ID = workerId; } public static long next() { return nextKey(); } public static String nextString() { return String.valueOf(next()); } private static synchronized long nextKey() { long currentMillis = System.currentTimeMillis(); Preconditions.checkState(LAST_TIME <= currentMillis, "Clock is moving backwards, last time is %d milliseconds, current time is %d milliseconds", LAST_TIME, currentMillis); if (LAST_TIME == currentMillis) { if (0L == (SEQUENCE = SEQUENCE + 1L & 4095L)) { currentMillis = waitUntilNextTime(currentMillis); } } else { SEQUENCE = 0L; } LAST_TIME = currentMillis; return currentMillis - EPOCH << 22 | WORKER_ID << 12 | SEQUENCE; } private static long waitUntilNextTime(final long lastTime) { long time; for(time = System.currentTimeMillis(); time <= lastTime; time = System.currentTimeMillis()) { } return time; } }