雪花算法生产的Id 的结果是一个64bit大小的整数
- 1位 ,不用。二进制中最高位为1的都是附属,但是我们生产的id一般都是使用整数,所以这个最高位固定是0
- 41位,用来记录时间戳
- 10位,用来记录工作机器ID
- 12位,序列号,用来记录同好卖哦内生产的不同ID
雪花优势:
- 1.所有生成的id按时间递增
- 2.整个分布式系统内不会生产重复ID
JAVA代码实现
/**
* @Description 雪花主键ID生成
* @Author qi
**/
public class SnowflakeIdGenerate implements IdGenerate<Long> {
/**
* 开始时间戳
*/
private final long twepoch = 1420041600000L;
/**
* 机器id所占的位数
*/
private final long workerIdBits = 5L;
/**
* 数据标识id所占的位数
*/
private final long dataCenterIdBits = 5L;
/**
* 支持的最大机器ID,结果是31(位移算法可以很快计算出二进制所能表示的最大十进制数)
*/
private final long maxWorkerId = -1L^(-1L<<workerIdBits);
/**
* 支持的最大数据标识DI,结果是31
*/
private final long maxDataCenterId = -1L^(-1L<<dataCenterIdBits);
/**
* 序列在id中咱的位数
*/
private final long sequenceBits = 12L;
/**
* 机器ID向左位移12位
*/
private final long workerIdShift = sequenceBits;
/**
* 数据标识ID向左位移17位(12+5)
*/
private final long dataCenterIdShift = sequenceBits+workerIdBits;
/**
* 时间戳向左位移22位(12+5+5)
*/
private final long timestampLeftShift =sequenceBits+workerIdBits+dataCenterIdShift;
/**
* 生成序列的掩码,这里为4095
*/
private final long sequenceMask = -1L^(-1L<<sequenceBits);
/**
* 工作机器ID(0-31)
*/
private long workerId;
/**
* 数据中心ID(0-31)
*/
private long dataCenterId;
/**
* 毫秒内序列(0-4095)
*/
private long sequence = 0L;
/**
* 上次生成ID的时间戳
*/
private long lastTimeStamp = -1L;
/**
* 构造方法
* @param workerId 机器ID
* @param dataCenterId 数据中心ID
*/
public SnowflakeIdGenerate(long workerId, long dataCenterId) {
if (workerId>maxWorkerId||workerId<0){
throw new IllegalArgumentException();
}
if (dataCenterId>maxDataCenterId||dataCenterId<0){
throw new IllegalArgumentException();
}
this.workerId = workerId;
this.dataCenterId = dataCenterId;
}
@Override
public synchronized Long nextId() {
long timestamp = timeGen();
if (timestamp<lastTimeStamp){
throw new RuntimeException(
String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimeStamp - timestamp));
}
if (lastTimeStamp == timestamp){
sequence = (sequence+1)&sequenceMask;
if (sequenceMask == 0){
timestamp = tilNextMillis(lastTimeStamp);
}
}else {
sequence = 0L;
}
//上次生成ID的时间戳
lastTimeStamp = timestamp;
return ((timestamp-twepoch)<<timestampLeftShift)
|(dataCenterId<<dataCenterIdShift)
|(workerId<<workerIdShift)
|sequence;
}
/**
* 阻塞到下一个毫秒,知道获取新的时间戳
* @param lastTimestamp
* @return
*/
private long tilNextMillis(long lastTimestamp){
long timestamp = timeGen();
while (timestamp<=lastTimestamp){
timestamp = timeGen();
}
return timestamp;
}
/**
* 获取当前时间戳
* @return
*/
private long timeGen(){
return System.currentTimeMillis();
}
}
注意:本文归作者所有,未经作者允许,不得转载