Skip to content

Commit 98c9f09

Browse files
committed
add SnowflakeIdWorker
1 parent 8cfa681 commit 98c9f09

File tree

2 files changed

+97
-0
lines changed

2 files changed

+97
-0
lines changed
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
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+
}

src/test/java/com/github/myibu/algorithm/AlgorithmTest.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import com.github.myibu.algorithm.hash.MurmurHash2;
1010
import com.github.myibu.algorithm.hash.SHA256;
1111
import com.github.myibu.algorithm.hash.SipHash;
12+
import com.github.myibu.algorithm.id.SnowflakeIdWorker;
1213
import com.github.myibu.algorithm.random.LinearCongruentialRandom;
1314
import com.github.myibu.algorithm.random.MersenneTwisterRandom;
1415
import com.github.myibu.algorithm.random.Random;
@@ -379,4 +380,13 @@ public void testBitsEncoder() {
379380
Assert.assertEquals(-2, Bits.Decoder.decodeZigzagValue(3));
380381
Assert.assertEquals(-1, Bits.Decoder.decodeZigzagValue(1));
381382
}
383+
384+
@Test
385+
public void testSnowflakeIdWorker() {
386+
SnowflakeIdWorker idWorker = new SnowflakeIdWorker(0, 0);
387+
for (int i = 0; i < 1000; i++) {
388+
long id = idWorker.nextId();
389+
System.out.println(id);
390+
}
391+
}
382392
}

0 commit comments

Comments
 (0)