IdWorker.java
4.89 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
137
138
139
140
141
142
143
package com.yoho.pay;
import com.yoho.core.common.utils.TimeUtils;
public class IdWorker{
private long workerId;
private long datacenterId;
private long sequence=0;
public IdWorker(long workerId, long datacenterId){
// sanity check for workerId
if (workerId > maxWorkerId || workerId < 0) {
throw new IllegalArgumentException(String.format("worker CodeMeta can't be greater than %d or less than 0",maxWorkerId));
}
if (datacenterId > maxDatacenterId || datacenterId < 0) {
throw new IllegalArgumentException(String.format("datacenter CodeMeta can't be greater than %d or less than 0",maxDatacenterId));
}
System.out.printf("worker starting. timestamp left shift %d, datacenter id bits %d, worker id bits %d, sequence bits %d, workerid %d",
timestampLeftShift, datacenterIdBits, workerIdBits, sequenceBits, workerId);
this.workerId = workerId;
this.datacenterId = datacenterId;
}
private long twepoch = 1288834974657L; // 起始时间戳
// 1位(固定值0) 21位(时间戳) 2+2位(工作机器id=5位的datacenterId + 5位的workerId) 12位(序号位)
// 一共64位,2的64位,最大能表示多少啊
private long workerIdBits = 2L;
private long datacenterIdBits = 2L;
// 可以表示的最大正整数 2的N次方-1, 值为31
private long maxWorkerId = -1L ^ (-1L << workerIdBits);
// 可以标识的最大正整数 2的N次方-1,值为31
private long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
private long sequenceBits = 12L;
// 左移12位
private long workerIdShift = sequenceBits;
// 左移 12+5位
private long datacenterIdShift = sequenceBits + workerIdBits;
// 左移 12+5+5 位
private long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
private long tmp = timestampLeftShift + 41L;
// 4095 2的n次方-1
private long sequenceMask = -1L ^ (-1L << sequenceBits);
private long tmpMask = -1L ^ (-1L << tmp);;
private long lastTimestamp = -1L;
public long getWorkerId(){
return workerId;
}
public long getDatacenterId(){
return datacenterId;
}
public long getTimestamp(){
return System.currentTimeMillis();
}
public synchronized long nextId() {
long timestamp = timeGen();
if (timestamp < lastTimestamp) {
System.err.printf("clock is moving backwards. Rejecting requests until %d.", lastTimestamp);
throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds",
lastTimestamp - timestamp));
}
// 获取当前时间,如果此刻的毫秒和 上次的毫秒是同一个时间点,则序号+1
if (lastTimestamp == timestamp) {
// 如果原来的序号+1 以后的结果是0,则说明这一毫秒可用的序列号都用完了,sequenceMask 都为0,要结果为0, 只能说明,左边的数据是0
// 一个数 与 一个全1的数字,不是还是等于左边的数吗?
sequence = (sequence + 1) & sequenceMask;
if (sequence == 0) {
timestamp = tilNextMillis(lastTimestamp);
}
} else {
sequence = 0;
}
lastTimestamp = timestamp;
// 最后返回 返回的结果如下:
return
(((timestamp - twepoch) << timestampLeftShift) & tmpMask)|
(datacenterId << datacenterIdShift) |
(workerId << workerIdShift) |
sequence;
}
private long tilNextMillis(long lastTimestamp) {
// 等待下一个毫秒
long timestamp = timeGen();
while (timestamp <= lastTimestamp) {
timestamp = timeGen();
}
return timestamp;
}
private long timeGen(){
return System.currentTimeMillis();
}
//---------------测试---------------
public static void main(String[] args) {
// IdWorker worker = new IdWorker(1,1);
// for (int i = 0; i < 30; i++) {
// System.out.println(worker.nextId());
// }
// 现在的生成结果
// 1041255103765549057
// 生成一个时间错 左移22位, long 64位,左移以后超过64位的都被只设置未0, 毫秒需要41位来表示吗
// xxxxxx
// 00000000xxxxxxx22位 则相当于时间戳位 有20位
// 与 位数最高位,全一的数据与一下 ====> 超过最高位的左边都会与成0,从而将数限制在范围内
System.out.println((System.currentTimeMillis() - 1288834974657L)<<22);
// // 1000000000010
// // 0111111111111
// // 这样起到的作用,将位数超过的高位直接设置成0了,保证数据在 指定的位数之内,防止位数溢出
// System.out.println(4095 & 4098);
}
}