基于时间随机数的流水号生成方案

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
public class IdGen {

private final int len;

private final int seqBit;

private final int randomBit;

private final int workBit;

private final int workerId;

private long lastTimestamp = 0L;

private long sequence = 0L;

private static final BigInteger UNIT = new BigInteger("10");

private DateTimeFormatter FORMAT;

/**
*
* @param len 长度 只能14, 17
* @param seqBit 同一时间序号长度
* @param randomBit 随机数长度用于混淆
* @param workBit 机器号长度
* @param workerId 机器号id
*/
public IdGen(int len, int seqBit, int randomBit, int workBit , int workerId) {
if ((len == 17)) {
FORMAT = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS");
} else if ((len == 14)) {
FORMAT = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
} else {
throw new IllegalArgumentException("时间长度只能为14或17");
}

this.workerId = workerId;
this.seqBit = seqBit;
this.workBit = workBit;
this.randomBit = randomBit;
this.len = len;
int maxValue = (UNIT.pow(workBit).intValue() - 1);
if (workerId > maxValue || workerId < 0) {
throw new IllegalArgumentException(String.format("workerId不能大于[%d],且不能小于0", maxValue));
}
}

public synchronized String nextId() {
long timestamp = now();

if (timestamp < lastTimestamp) {
throw new RuntimeException(String.format("时钟倒退[%s]ms", lastTimestamp - timestamp));
}

if (lastTimestamp == timestamp) {
sequence = sequence + 1;
// 当前毫秒内计数满了,则等待下一毫秒
if (sequence > (UNIT.pow(seqBit).intValue()-1)) {
timestamp = nextMillis(lastTimestamp);
}
} else {
sequence = 0L;
}
lastTimestamp = timestamp;

int random = ThreadLocalRandom.current().nextInt(0, UNIT.pow(randomBit).intValue());
return String.format("%0"+len+"d", timestamp) +
String.format("%0"+seqBit+"d", sequence) +
String.format("%0"+randomBit+"d", random) +
String.format("%0"+workBit+"d", workerId) ;
}
private long nextMillis(final long lastTimestamp) {
long timestamp = this.now();
while (timestamp <= lastTimestamp) {
timestamp = this.now();
}
return timestamp;
}

private long now() {
LocalDateTime dateTime = LocalDateTime.now();
return Long.parseLong(dateTime.format(FORMAT));
}

public static void main(String[] args) {
// 方案1
IdGen gen1 = new IdGen(17, 3, 2,2, 1);
System.out.println(gen1.nextId());
// 方案2
IdGen gen2 = new IdGen(14, 2, 2,1, 1);
System.out.println(gen2.nextId());

// 202304251014103330008201
// 2023042510141000441

}
}