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());
|
}*/
|
|
}
|