import lombok.extern.slf4j.Slf4j;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* 根据虚化算法改造,生成带时间戳的全局唯一ID
* 仅适用于机器IP后缀不同使用
* 无关机房,IP地址尾号一样的不适用,可能会出现重复ID问题
*
*
* @Author: ylj
* @Date: 2023/11/20
*/
@Slf4j
public class UniqueIdUtils {
/**
* 代表每毫秒内可产生最大序列号,即9999
*/
private static final int MAX_SEQ = 9999;
/**
* 序列号初始值
*/
private static long sequence = 10;
/**
* 初始化机器码,区分不通机器
*
*/
private static String WORK_ID = "00";
/**
* 记录最后使用的毫秒时间戳,主要用于判断是否同一毫秒
*/
private long lastTimeMillis = -1L;
/**
* 初始化
*/
static {
try {
String ip = getIp();
WORK_ID = ip.substring(ip.lastIndexOf(".") + 1);
} catch (UnknownHostException e) {
log.warn("unknown host exception:{}", e.getMessage());
}
}
/**
* 生成全局唯一ID
* @return
*/
public synchronized String nextId(){
// 获取当前时间戳,单位为毫秒
long currentTimeMillis = System.currentTimeMillis();
// 当前时间小于上一次生成id使用的时间,可能出现服务器时钟回拨问题
if (currentTimeMillis < lastTimeMillis) {
throw new RuntimeException(
String.format("可能出现服务器时钟回拨问题,请检查服务器时间。当前服务器时间戳:%d,上一次使用时间戳:%d",
currentTimeMillis, lastTimeMillis));
}
if (lastTimeMillis == currentTimeMillis) {
sequence = sequence + 1;
//如果序号到达最大值,获取下一毫秒时间的序号值
if (sequence == MAX_SEQ){
currentTimeMillis = tilNextMillis(lastTimeMillis);
//重置序号
sequence = 10;
}
}else{
//重置序号
sequence = 10;
}
StringBuffer sb = new StringBuffer();
sb.append(WORK_ID).append(currentTimeMillis).append(sequence);
lastTimeMillis = currentTimeMillis;
return sb.toString();
}
private static long tilNextMillis(long lastTimestamp) {
// 获取当前时间戳,单位为毫秒
long timestamp = timeGen();
// 如果当前时间戳小于等于上一个生成ID的时间戳,则等待下一毫秒
int i = 0;
while (timestamp <= lastTimestamp) {
System.out.println(++i);
timestamp = timeGen();
}
i= 0;
return timestamp;
}
/**
* 获取当前时间戳(毫秒级)
*
* @return 当前时间戳
*/
private static long timeGen() {
return System.currentTimeMillis();
}
private static String getIp() throws UnknownHostException{
InetAddress ip = InetAddress.getLocalHost();
System.out.println("IP地址: " + ip.getHostAddress());
return ip.getHostAddress();
}
public static void main(String[] args) {
UniqueIdUtils gerator = new UniqueIdUtils();
for (int i = 0; i < 10000; i++) {
System.out.println(gerator.nextId());
}
}
}
根据雪花算法生成带时间戳的全局唯一ID
最新推荐文章于 2024-04-17 10:19:41 发布