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
|
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicLong;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class IdGenerator {
private static final Logger log = LoggerFactory.getLogger(IdGenerator.class);
private static IdGenerator INSTANCE = new IdGenerator();
private long machineId;
private AtomicLong lastId;
private long twepoch = 1561910400000L; // 基准时间 2019-07-01 00:00:00
private long machineIdBits = 10L;
private long maxMachineId = -1L ^ (-1L << machineIdBits);
private long sequenceBits = 10L;
private long machineIdShift = sequenceBits;
private long timestampLeftShift = sequenceBits + machineIdBits;
private long maxSequence = (-1L ^ (-1L << sequenceBits)) - 1L;// 序列号的最大值
private long sequenceMask = (-1L ^ (-1L << sequenceBits));
private IdGenerator() {
}
public static IdGenerator getInstance() {
return INSTANCE;
}
public void init(long machineId) {
// sanity check for workerId
if (machineId > maxMachineId || machineId < 0) {
throw new IllegalArgumentException(
String.format("machine Id can't be greater than %d or less than 0", maxMachineId));
}
log.info("ID generator starting. timestamp left shift " + timestampLeftShift + ", machine id bits "
+ machineIdBits + ", sequence bits " + sequenceBits + ", machineId " + machineId);
this.machineId = machineId;
lastId = new AtomicLong((timeGen() - twepoch) << timestampLeftShift | randStartSequence());
}
private long randStartSequence() {
return ThreadLocalRandom.current().nextInt(10);
}
/**
* 最高位固定为0
* +------------------------+---------------------------+-----------------+
* | 43bits timestamp in ms | 10bits worker(machine) ID | 10bits sequence |
* +------------------------+---------------------------+-----------------+
* @return
*/
public long generateId() {
while (true) {
long now = timeGen();
long oldId = lastId.get();
long lastTimeInterval = oldId >>> timestampLeftShift;
long nowInterval = now - twepoch;
long sequence;
if (nowInterval < lastTimeInterval) {
Thread.yield();
continue;
} else if (nowInterval == lastTimeInterval) {
sequence = oldId & sequenceMask;
if (sequence >= maxSequence) {
now = tillNextMillis(now);
nowInterval = now - twepoch;
sequence = randStartSequence();
} else {
sequence = sequence + 1;
}
} else {
sequence = randStartSequence();
}
long newId = (nowInterval << timestampLeftShift) | (machineId << machineIdShift) | sequence;
if (!lastId.compareAndSet(oldId, newId)) {
Thread.yield();
continue;
}
return newId;
}
}
private long tillNextMillis(long lastTimestamp) {
long timestamp = timeGen();
while (timestamp <= lastTimestamp) {
Thread.yield();
timestamp = timeGen();
}
return timestamp;
}
private long timeGen(){
return System.currentTimeMillis();
}
}
|