CZT
2023-12-21 d1b7f2eb67cd87edc4b5eb11def5acba07c75698
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
package com.fzzy.api.utils;
 
public class SnowflakeIdWorker {
 
    //下面两个每个5位,加起来就是10位的工作机器id
    private static long workerId = 2;    //工作id
    private  static long datacenterId =2;   //数据id
    //12位的序列号
    private static long sequence = 2;
 
    public   SnowflakeIdWorker(long workerId, long datacenterId, long sequence){
        // sanity check for workerId
        if (workerId > maxWorkerId || workerId < 0) {
            throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0",maxWorkerId));
        }
        if (datacenterId > maxDatacenterId || datacenterId < 0) {
            throw new IllegalArgumentException(String.format("datacenter Id 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);
 
        SnowflakeIdWorker.workerId = workerId;
        SnowflakeIdWorker.datacenterId = datacenterId;
        SnowflakeIdWorker.sequence = sequence;
    }
 
    //初始时间戳
    private static long twepoch = 1645587680;
 
    //长度为5位
    private static long workerIdBits = 5L;
    private static long datacenterIdBits = 5L;
    //最大值
    private static long maxWorkerId = -1L ^ (-1L << workerIdBits);
    private static long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
    //序列号id长度
    private static long sequenceBits = 12L;
    //序列号最大值
    private static long sequenceMask = -1L ^ (-1L << sequenceBits);
 
    //工作id需要左移的位数,12位
    private static long workerIdShift = sequenceBits;
    //数据id需要左移位数 12+5=17位
    private static long datacenterIdShift = sequenceBits + workerIdBits;
    //时间戳需要左移位数 12+5+5=22位
    private static long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
 
    //上次时间戳,初始值为负数
    private static long lastTimestamp = -1L;
 
    public static long getWorkerId(){
        return workerId;
    }
 
    public static long getDatacenterId(){
        return datacenterId;
    }
 
    public static long getTimestamp(){
        return System.currentTimeMillis();
    }
 
    //下一个ID生成算法
    public synchronized static long nextId() {
        long timestamp = SnowflakeIdWorker.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));
        }
 
        //获取当前时间戳如果等于上次时间戳(同一毫秒内),则在序列号加一;否则序列号赋值为0,从0开始。
        if (lastTimestamp == timestamp) {
            sequence = (sequence + 1) & sequenceMask;
            if (sequence == 0) {
                timestamp = tilNextMillis(lastTimestamp);
            }
        } else {
            sequence = 0;
        }
 
        //将上次时间戳值刷新
        lastTimestamp = timestamp;
 
        /**
         * 返回结果:
         * (timestamp - twepoch) << timestampLeftShift) 表示将时间戳减去初始时间戳,再左移相应位数
         * (datacenterId << datacenterIdShift) 表示将数据id左移相应位数
         * (workerId << workerIdShift) 表示将工作id左移相应位数
         * | 是按位或运算符,例如:x | y,只有当x,y都为0的时候结果才为0,其它情况结果都为1。
         * 因为个部分只有相应位上的值有意义,其它位上都是0,所以将各部分的值进行 | 运算就能得到最终拼接好的id
         */
        return ((timestamp - twepoch) << timestampLeftShift) |
                (datacenterId << datacenterIdShift) |
                (workerId << workerIdShift) |
                sequence;
    }
 
    //获取时间戳,并与上次时间戳比较
    private static long  tilNextMillis(long lastTimestamp) {
        long timestamp = timeGen();
        while (timestamp <= lastTimestamp) {
            timestamp = timeGen();
        }
        return timestamp;
    }
 
    //获取系统时间戳
    private static  long  timeGen(){
        return System.currentTimeMillis();
    }
 
    //---------------测试---------------
    public static void main(String[] args) {
 
     // SnowflakeIdWorker    snowflakeIdWorker=  new SnowflakeIdWorker(2,2,2);
        for (int i = 0; i < 30; i++) {
            System.out.println(SnowflakeIdWorker.nextId());
        }
    }
 
 
 
 
 
 
}