郑永安
2023-06-19 7a6abd05683528032687c75e80e0bd2030a3e46c
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
package com.gkhy.safePlatform.commons.utils.idService;
 
public class IdGenerateUtil {
    // 起始的时间戳
    private final static long START_STMP = 1577808000000L; //2020-01-01
    // 每一部分占用的位数,就三个
    private final static long SEQUENCE_BIT = 10; //序列号占用的位数
    private final static long TABLE_BIT = 7; //数据库表占用的位数
    private final static long BIZ_BIT = 5; //业务占用的位数
    // 每一部分最大值
    private final static long MAX_BIZ_NUM = -1L ^ (-1L << BIZ_BIT);
    private final static long MAX_TABLE_NUM = -1L ^ (-1L << TABLE_BIT);
    private final static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BIT);
    // 每一部分向左的位移
    private final static long MACHINE_LEFT = SEQUENCE_BIT;
    private final static long DATACENTER_LEFT = SEQUENCE_BIT + TABLE_BIT;
    private final static long TIMESTMP_LEFT = DATACENTER_LEFT + BIZ_BIT;
    private long bizId; //业务标识
    private long tableId; //数据库表标识
    private long sequence = 0L; //序列号
    private long lastStmp = -1L; //上一次时间戳
 
    public IdGenerateUtil() {
    }
 
    //    public SnowFlakeUtil(long bizId, long tableId) {
//        if (bizId > MAX_BIZ_NUM || bizId < 0) {
//            throw new IllegalArgumentException("bizId can't be greater than MAX_BIZ_NUM or less than 0");
//        }
//        if (tableId > MAX_TABLE_NUM || tableId < 0) {
//            throw new IllegalArgumentException("tableId can't be greater than MAX_TABLE_NUM or less than 0");
//        }
//        this.bizId = bizId;
//        this.tableId = tableId;
//    }
 
    public synchronized long nextId(long bizId, long tableId) {
        if (bizId > MAX_BIZ_NUM || bizId < 0) {
            throw new IllegalArgumentException("bizId can't be greater than MAX_BIZ_NUM or less than 0");
        }
        if (tableId > MAX_TABLE_NUM || tableId < 0) {
            throw new IllegalArgumentException("tableId can't be greater than MAX_TABLE_NUM or less than 0");
        }
        long currStmp = timeGen();
        if (currStmp < lastStmp) {
            throw new RuntimeException("Clock moved backwards. Refusing to generate id");
        }
 
        if (currStmp == lastStmp) {
            //if条件里表示当前调用和上一次调用落在了相同毫秒内,只能通过第三部分,序列号自增来判断为唯一,所以+1.
            sequence = (sequence + 1) & MAX_SEQUENCE;
            //同一毫秒的序列数已经达到最大,只能等待下一个毫秒
            if (sequence == 0L) {
                currStmp = getNextMill();
            }
        } else {
            //不同毫秒内,序列号置为0
//执行到这个分支的前提是currTimestamp > lastTimestamp,说明本次调用跟上次调用对比,已经不再同一个毫秒内了,这个时候序号可以重新回置0了。
            sequence = 0L;
        }
 
        lastStmp = currStmp;
        //就是用相对毫秒数、机器ID和自增序号拼接
        return (currStmp - START_STMP) << TIMESTMP_LEFT //时间戳部分
                | bizId << DATACENTER_LEFT //业务部分
                | tableId << MACHINE_LEFT //数据库表部分
                | sequence; //序列号部分
    }
 
    //产生下一个ID
    public synchronized long nextId() {
        long currStmp = timeGen();
        if (currStmp < lastStmp) {
            throw new RuntimeException("Clock moved backwards. Refusing to generate id");
        }
 
        if (currStmp == lastStmp) {
            //if条件里表示当前调用和上一次调用落在了相同毫秒内,只能通过第三部分,序列号自增来判断为唯一,所以+1.
            sequence = (sequence + 1) & MAX_SEQUENCE;
            //同一毫秒的序列数已经达到最大,只能等待下一个毫秒
            if (sequence == 0L) {
                currStmp = getNextMill();
            }
        } else {
            //不同毫秒内,序列号置为0
//执行到这个分支的前提是currTimestamp > lastTimestamp,说明本次调用跟上次调用对比,已经不再同一个毫秒内了,这个时候序号可以重新回置0了。
            sequence = 0L;
        }
 
        lastStmp = currStmp;
        //就是用相对毫秒数、机器ID和自增序号拼接
        return (currStmp - START_STMP) << TIMESTMP_LEFT //时间戳部分
                | bizId << DATACENTER_LEFT //业务部分
                | tableId << MACHINE_LEFT //数据库表部分
                | sequence; //序列号部分
    }
 
    private long getNextMill() {
        long mill = timeGen();
        while (mill <= lastStmp) {
            mill = timeGen();
        }
        return mill;
    }
 
    private long timeGen() {
        return System.currentTimeMillis();
    }
 
/*      // 测试
     public static void main(String[] args) {
 
        SnowFlake snowFlow = new SnowFlake(1, 1);
//        for (int i = 0; i < 3; i++) {
//            System.out.println(snowFlow.nextId());
//        }
        System.out.println(snowFlow.nextId());
    }*/
 
}