SnowFlakeUtil.java
4.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
package org.nafmii.utils;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
/**
* @description: 雪花算法
* @author: DINGZIYAO
* @date: 2020/9/14 13:59
* @version: v1.0
*/
public class SnowFlakeUtil {
private final static long TWEPOCH = 12888349746579L;
// 机器标识位数
private final static long WORKER_ID_BITS = 5L;
// 数据中心标识位数
private final static long DATACENTER_ID_BITS = 5L;
// 毫秒内自增位数
private final static long SEQUENCE_BITS = 12L;
// 机器ID偏左移12位
private final static long WORKER_ID_SHIFT = SEQUENCE_BITS;
// 数据中心ID左移17位
private final static long DATACENTER_ID_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS;
// 时间毫秒左移22位
private final static long TIMESTAMP_LEFT_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS + DATACENTER_ID_BITS;
//sequence掩码,确保sequnce不会超出上限
private final static long SEQUENCE_MASK = ~(-1L << SEQUENCE_BITS);
//上次时间戳
private static long lastTimestamp = -1L;
//序列
private long sequence = 0L;
//服务器ID
private long workerId = 1L;
private static final long WORKER_MASK = ~(-1L << WORKER_ID_BITS);
//进程编码
private long processId = 1L;
private static final long PROCESS_MASK = ~(-1L << DATACENTER_ID_BITS);
private static SnowFlakeUtil snowFlake = null;
static{
snowFlake = new SnowFlakeUtil();
}
public static synchronized long nextId(){
return snowFlake.getNextId();
}
private SnowFlakeUtil() {
//获取机器编码
this.workerId=this.getMachineNum();
//获取进程编码
RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
this.processId= Long.parseLong(runtimeMXBean.getName().split("@")[0]);
//避免编码超出最大值
this.workerId=workerId & WORKER_MASK;
this.processId=processId & PROCESS_MASK;
}
public synchronized long getNextId() {
//获取时间戳
long timestamp = timeGen();
//如果时间戳小于上次时间戳则报错
if (timestamp < lastTimestamp) {
try {
throw new Exception("Clock moved backwards. Refusing to generate id for " + (lastTimestamp - timestamp) + " milliseconds");
} catch (Exception e) {
e.printStackTrace();
}
}
//如果时间戳与上次时间戳相同
if (lastTimestamp == timestamp) {
// 当前毫秒内,则+1,与sequenceMask确保sequence不会超出上限
sequence = (sequence + 1) & SEQUENCE_MASK;
if (sequence == 0) {
// 当前毫秒内计数满了,则等待下一秒
timestamp = tilNextMillis(lastTimestamp);
}
} else {
sequence = 0;
}
lastTimestamp = timestamp;
// ID偏移组合生成最终的ID,并返回ID
long nextId = ((timestamp - TWEPOCH) << TIMESTAMP_LEFT_SHIFT) | (processId << DATACENTER_ID_SHIFT) | (workerId << WORKER_ID_SHIFT) | sequence;
return nextId;
}
/**
* 再次获取时间戳直到获取的时间戳与现有的不同
* @param lastTimestamp
* @return 下一个时间戳
*/
private long tilNextMillis(final long lastTimestamp) {
long timestamp = this.timeGen();
while (timestamp <= lastTimestamp) {
timestamp = this.timeGen();
}
return timestamp;
}
private long timeGen() {
return System.currentTimeMillis();
}
/**
* 获取机器编码
* @return
*/
private long getMachineNum(){
long machinePiece;
StringBuilder sb = new StringBuilder();
Enumeration<NetworkInterface> e = null;
try {
e = NetworkInterface.getNetworkInterfaces();
} catch (SocketException e1) {
e1.printStackTrace();
}
while (e.hasMoreElements()) {
NetworkInterface ni = e.nextElement();
sb.append(ni.toString());
}
machinePiece = sb.toString().hashCode();
return machinePiece;
}
public static void main(String[] args) {
System.out.println(SnowFlakeUtil.nextId());
// 8073480304000524288
// 8073480926335623168
}
}