com.gitee.cn9750wang.webtools.utils.SnowFlakeIdGenerator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of web-tools Show documentation
Show all versions of web-tools Show documentation
web tools for spring-boot web project
The newest version!
/*
* Copyright 2021 wwy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.gitee.cn9750wang.webtools.utils;
import com.gitee.cn9750wang.webtools.error.defines.ParamErr;
/**
* 雪花算法ID生成器
* 生成的ID由 1bit符号位 + 41bit时间偏移量 + 5bit数据中心ID + 5bit机器ID + 12bit序列号 组成
* 其中 5bit数据中心ID+5bit机器ID 组成服务器ID,服务器ID总计1024个
* @author wwy
*/
public class SnowFlakeIdGenerator {
/**
* 服务器id
* 由 5bit数据中心ID+5bit机器ID 组成服务器ID
*/
private final long serverId;
/** 12位的序列号 */
private long sequence = -1;
/** 初始时间戳 2020-01-01 */
private static final long START_TIMESTAMP = 1577808000000L;
/** 上一次获取的时间戳 */
private long lastTimestamp = 0;
/** 递增序号 长度 */
private static final long SEQUENCE_SIZE = 12;
/** 数据中心ID或机器ID 长度 */
private static final long DATA_CENTER_ID_SIZE = 5;
/** 服务器ID 长度 */
private static final long SERVER_ID_SIZE = DATA_CENTER_ID_SIZE * 2;
/** 时间戳 长度 */
private static final long TIMESTAMP_SIZE = 41;
/** 零 */
private static final byte ZERO = 0;
/** 服务器ID最大值 */
private static final short MAX_SERVER_ID = 1 << SERVER_ID_SIZE - 1;
/** 数据中心ID或机器ID最大值 */
private static final byte MAX_DATA_CENTER_ID = 1 << DATA_CENTER_ID_SIZE - 1;
/** 递增序号最大值 */
private static final short MAX_SEQUENCE = 1 << SEQUENCE_SIZE - 1;
/** 时间戳裁剪 */
private static final long TIMESTAMP_CUT = ~(-1L << TIMESTAMP_SIZE);
/** 时间戳左移值 */
private static final long TIMESTAMP_LEFT_SHIFT = SERVER_ID_SIZE + SEQUENCE_SIZE;
private SnowFlakeIdGenerator(final int serverId){
this.serverId = (long) serverId << SEQUENCE_SIZE;
}
/**
* 获取雪花ID生成器
* @param serverId 服务器ID 10bit组成
* @return 雪花ID生成器
*/
public static SnowFlakeIdGenerator getInstance(final int serverId){
if(serverId < ZERO || serverId > MAX_SERVER_ID){
checkValueBetweenThrow("serverId", MAX_SERVER_ID);
}
return new SnowFlakeIdGenerator(serverId);
}
/**
* 获取雪花ID生成器
* @param dataCenterId 数据中心ID 5bit组成
* @param workerId 机器ID 5bit组成
* @return 雪花ID生成器
*/
public static SnowFlakeIdGenerator getInstance(final int dataCenterId,final int workerId){
if(dataCenterId < ZERO || dataCenterId > MAX_DATA_CENTER_ID){
checkValueBetweenThrow("dataCenterId", MAX_DATA_CENTER_ID);
}
if(workerId < ZERO || workerId > MAX_DATA_CENTER_ID){
checkValueBetweenThrow("workerId", MAX_DATA_CENTER_ID);
}
int serverId = dataCenterId;
serverId <<= 5;
serverId += workerId;
return getInstance(serverId);
}
/** 生成异常对象 */
private static void checkValueBetweenThrow(String valueName, long max){
ParamErr.BETWEEN.format(valueName,SnowFlakeIdGenerator.ZERO,max).throwErr();
}
/**
* 获取雪花算法生成的ID
* @return 雪花算法生成的ID
*/
public long nextId() {
// 获取时间戳
final var timestamp = System.currentTimeMillis() - START_TIMESTAMP;
// 服务器计数器
final long sequence;
// 对象加锁,校验时间戳和设置计数器
synchronized (this){
// 如果时间戳小于上次的时间戳
if(timestamp < this.lastTimestamp){
throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds",lastTimestamp));
}
// 如果与上次时间戳相等,序号自增
if(timestamp == this.lastTimestamp){
this.sequence++;
// 掐头,掐去超出12位的部分
// this.sequence &= (Short.MAX_VALUE ^ (Short.MAX_VALUE << 12));
if(this.sequence > MAX_SEQUENCE){
try {
Thread.sleep(0);
}catch (InterruptedException e){
e.printStackTrace();
}
return nextId();
}
}
// 否则重新计数
else {
this.sequence = 0;
}
// 刷新时间戳
this.lastTimestamp = timestamp;
sequence = this.sequence;
}
// 41bit时间戳,先 左移22位
final var timestamp41bit = (timestamp & TIMESTAMP_CUT) << TIMESTAMP_LEFT_SHIFT;
// 计算雪花算法得到的值
return timestamp41bit | serverId | sequence;
}
}