Skip to content

Commit 1a9104f

Browse files
committed
雪花算法
1 parent af5d4d9 commit 1a9104f

File tree

1 file changed

+165
-0
lines changed

1 file changed

+165
-0
lines changed
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
package code.distribution.id.Snowflake;
2+
3+
/**
4+
* 〈Snowflake算法〉<p>
5+
* 〈功能详细描述〉
6+
* @see https://github.com/seata/seata/blob/1.4.0/common/src/main/java/io/seata/common/util/IdWorker.java
7+
* @author tianwu
8+
* @date 2021/06/16
9+
*/
10+
import java.net.InetAddress;
11+
import java.net.UnknownHostException;
12+
import java.util.concurrent.ThreadLocalRandom;
13+
14+
public class IdWorker {
15+
16+
private volatile static IdWorker idWorker = null;
17+
18+
/**
19+
* Start time cut (2020-05-03)
20+
*/
21+
private final long twepoch = 1588435200000L;
22+
23+
/**
24+
* The number of bits occupied by the machine id
25+
*/
26+
private final long workerIdBits = 10L;
27+
28+
/**
29+
* Maximum supported machine id, the result is 1023 (this shift algorithm can quickly calculate the largest decimal
30+
* number that can be represented by a few binary numbers)
31+
*/
32+
private final long maxWorkerId = -1L ^ (-1L << workerIdBits);
33+
34+
/**
35+
* The number of bits the sequence occupies in id
36+
*/
37+
private final long sequenceBits = 12L;
38+
39+
/**
40+
* Machine ID left 12 digits
41+
*/
42+
private final long workerIdShift = sequenceBits;
43+
44+
/**
45+
* Time truncated to the left by 22 bits (10 + 12)
46+
*/
47+
private final long timestampLeftShift = sequenceBits + workerIdBits;
48+
49+
/**
50+
* Generate sequence mask
51+
*/
52+
private final long sequenceMask = -1L ^ (-1L << sequenceBits);
53+
54+
/**
55+
* Machine ID (0 ~ 1023)
56+
*/
57+
private long workerId;
58+
59+
/**
60+
* Sequence in milliseconds (0 ~ 4095)
61+
*/
62+
private long sequence = 0L;
63+
64+
/**
65+
* Time of last ID generation
66+
*/
67+
private long lastTimestamp = -1L;
68+
69+
/**
70+
* Constructor
71+
*
72+
* @param workerId
73+
* Job ID (0 ~ 1023)
74+
*/
75+
public IdWorker(long workerId) {
76+
if (workerId > maxWorkerId || workerId < 0) {
77+
throw new IllegalArgumentException(
78+
String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
79+
}
80+
this.workerId = workerId;
81+
}
82+
83+
/**
84+
* Get the next ID (the method is thread-safe)
85+
*
86+
* @return SnowflakeId
87+
*/
88+
public synchronized long nextId() {
89+
long timestamp = timeGen();
90+
91+
if (timestamp < lastTimestamp) {
92+
throw new RuntimeException(String.format(
93+
"clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
94+
}
95+
96+
if (lastTimestamp == timestamp) {
97+
sequence = (sequence + 1) & sequenceMask;
98+
if (sequence == 0) {
99+
timestamp = tilNextMillis(lastTimestamp);
100+
}
101+
} else {
102+
sequence = ThreadLocalRandom.current().nextLong(0, 256);
103+
}
104+
lastTimestamp = timestamp;
105+
106+
return ((timestamp - twepoch) << timestampLeftShift) | (workerId << workerIdShift) | sequence;
107+
}
108+
109+
/**
110+
* Block until the next millisecond until a new timestamp is obtained
111+
*
112+
* @param lastTimestamp
113+
* Time of last ID generation
114+
* @return Current timestamp
115+
*/
116+
protected long tilNextMillis(long lastTimestamp) {
117+
long timestamp = timeGen();
118+
while (timestamp <= lastTimestamp) {
119+
timestamp = timeGen();
120+
}
121+
return timestamp;
122+
}
123+
124+
/**
125+
* Returns the current time in milliseconds
126+
*
127+
* @return Current time (ms)
128+
*/
129+
protected long timeGen() {
130+
return System.currentTimeMillis();
131+
}
132+
133+
public static IdWorker getInstance() {
134+
if (idWorker == null) {
135+
synchronized (IdWorker.class) {
136+
if (idWorker == null) {
137+
init(initWorkerId());
138+
}
139+
}
140+
}
141+
return idWorker;
142+
}
143+
144+
public static long initWorkerId() {
145+
InetAddress address;
146+
try {
147+
address = InetAddress.getLocalHost();
148+
} catch (final UnknownHostException e) {
149+
throw new IllegalStateException("Cannot get LocalHost InetAddress, please check your network!",e);
150+
}
151+
byte[] ipAddressByteArray = address.getAddress();
152+
return ((ipAddressByteArray[ipAddressByteArray.length - 2] & 0B11) << Byte.SIZE) + (ipAddressByteArray[ipAddressByteArray.length - 1] & 0xFF);
153+
}
154+
155+
public static void init(Long serverNodeId) {
156+
if (idWorker == null) {
157+
synchronized (IdWorker.class) {
158+
if (idWorker == null) {
159+
idWorker = new IdWorker(serverNodeId);
160+
}
161+
}
162+
}
163+
}
164+
165+
}

0 commit comments

Comments
 (0)