1+ package com .github .myibu .algorithm .id ;
2+ 3+ /**
4+ * Twitter Snowflake
5+ * see <a href="https://github.com/twitter-archive/snowflake/blob/scala_28/src/main/scala/com/twitter/service/snowflake/IdWorker.scala">snowflake's IdWorker</a>
6+ * @author myibu
7+ * Created on 2022年10月12日
8+ */
9+ public class SnowflakeIdWorker {
10+ private final static long twepoch = 1598598185157L ;
11+ 12+ private long sequence = 0L ;
13+ private final static long workerIdBits = 5L ;
14+ private final static long datacenterIdBits = 5L ;
15+ private final static long maxWorkerId = -1L ^ (-1L << workerIdBits );
16+ private final static long maxDatacenterId = -1L ^ (-1L << datacenterIdBits );
17+ private final static long sequenceBits = 12L ;
18+ 19+ private final static long workerIdShift = sequenceBits ;
20+ private final static long datacenterIdShift = sequenceBits + workerIdBits ;
21+ private final static long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits ;
22+ private final static long sequenceMask = -1L ^ (-1L << sequenceBits );
23+ 24+ private long lastTimestamp = -1L ;
25+ 26+ private final long workerId ;
27+ private final long datacenterId ;
28+ 29+ public SnowflakeIdWorker (long workerId , long datacenterId ) {
30+ if (workerId > maxWorkerId || workerId < 0 ) {
31+ throw new IllegalArgumentException (String .format ("worker Id can't be greater than %d or less than 0" , maxWorkerId ));
32+ }
33+ if (datacenterId > maxDatacenterId || datacenterId < 0 ) {
34+ throw new IllegalArgumentException (String .format ("datacenter Id can't be greater than %d or less than 0" , maxDatacenterId ));
35+ }
36+ this .workerId = workerId ;
37+ this .datacenterId = datacenterId ;
38+ }
39+ 40+ public long getWorkerId () {
41+ return workerId ;
42+ }
43+ 44+ public long getDatacenterId () {
45+ return datacenterId ;
46+ }
47+ 48+ public long getTimestamp () {
49+ return System .currentTimeMillis ();
50+ }
51+ 52+ public synchronized long nextId () {
53+ long timestamp = timeGen ();
54+ 55+ if (lastTimestamp == timestamp ) {
56+ sequence = (sequence + 1 ) & sequenceMask ;
57+ if (sequence == 0 ) {
58+ timestamp = tilNextMillis (lastTimestamp );
59+ }
60+ } else {
61+ sequence = 0L ;
62+ }
63+ 64+ if (timestamp < lastTimestamp ) {
65+ throw new RuntimeException (String .format ("Clock moved backwards. Refusing to generate id for %d milliseconds" , lastTimestamp - timestamp ));
66+ }
67+ 68+ lastTimestamp = timestamp ;
69+ 70+ return ((timestamp - twepoch ) << timestampLeftShift )
71+ | (datacenterId << datacenterIdShift )
72+ | (workerId << workerIdShift )
73+ | sequence ;
74+ }
75+ 76+ protected long tilNextMillis (long lastTimestamp ) {
77+ long timestamp = timeGen ();
78+ while (timestamp <= lastTimestamp ) {
79+ timestamp = timeGen ();
80+ }
81+ return timestamp ;
82+ }
83+ 84+ protected long timeGen () {
85+ return System .currentTimeMillis ();
86+ }
87+ }
0 commit comments