package com.test;
import com.google.common.collect.Maps;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Description:
* 生成唯一键算法
*
* @Author: leo.xiong
* @CreateDate: 2021/5/14 13:55
* @Email: [email protected]
* @Since:
*/
public class GenerateAUniqueKey {
private static final Logger LOGGER = LoggerFactory.getLogger(GenerateAUniqueKey.class);
/**
* 首位
*/
private static final String FIRST_INDEX = "0";
/**
* IP,12位(IP是有可能改变的,所以这里需要考虑什么是服务器唯一,不能改变,MAC地址也是可以改变的,CPU等也是可以刷)
*/
private static String IP;
public static final String LOCAL_HOST = "127.0.0.1";
public static final String COLON = ":";
private static final int MAX_IP_LENGTH = 15;
private static final int MIN_IP_LENGTH = 7;
private static final String BASIC_BUSINESS = "basicBusiness";
/**
* 时间回拨最大尝试次数
*/
private static final int MAX_TRY_TIME = 5;
/**
* 最后一次时间
*/
private static Long lastTime;
static {
try {
Enumeration netInterfaces = NetworkInterface.getNetworkInterfaces();
while (netInterfaces.hasMoreElements()) {
Enumeration<InetAddress> ni = ((NetworkInterface) netInterfaces.nextElement()).getInetAddresses();
String ip;
if (ni.hasMoreElements()) {
ip = ni.nextElement().getHostAddress();
if (StringUtils.isEmpty(ip)) {
continue;
}
if (!LOCAL_HOST.equals(ip) && ip.indexOf(COLON) == -1 && isIP(ip)) {
IP = StringUtils.leftPad(ip.replace(".", ""), 12, '0');
}
}
}
} catch (SocketException e) {
}
}
private static boolean isIP(String addr) {
if (addr.length() < MIN_IP_LENGTH || addr.length() > MAX_IP_LENGTH || "".equals(addr)) {
return false;
}
/**
* 判断IP格式和范围
*/
String rexp = "([1-9]|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3}";
Pattern pat = Pattern.compile(rexp);
Matcher mat = pat.matcher(addr);
boolean ipAddress = mat.find();
return ipAddress;
}
/**
* 业务类型
*/
private static final Map<String, String> BUSINESS_INFORMATION_MAP = Maps.newHashMap();
/**
* 获取业务ID
* 6位
*
* @return
*/
private static String buildBusinessQueueId(String businessType) {
String queueId = BUSINESS_INFORMATION_MAP.get(businessType);
if (queueId == null) {
synchronized (BUSINESS_INFORMATION_MAP) {
Integer hashCode = Math.abs(businessType.hashCode());
if (hashCode > 999999) {
queueId = StringUtils.leftPad(String.valueOf(hashCode).substring(0, 6), 6, '0');
} else {
queueId = StringUtils.leftPad(String.valueOf(hashCode), 6, '0');
}
BUSINESS_INFORMATION_MAP.put(businessType, queueId);
}
}
return queueId;
}
private static final Map<String, String> TIME_SELF_INCREASING_MAP = new HashMap<>();
/**
* 8位自增序列号
*
* @return
*/
private synchronized static String selfIncreasing(String businessTypeTime) {
if (!TIME_SELF_INCREASING_MAP.containsKey(businessTypeTime)) {
TIME_SELF_INCREASING_MAP.clear();
}
String serialNumber = TIME_SELF_INCREASING_MAP.get(businessTypeTime);
Long value = 0L;
if (serialNumber != null) {
value = Long.valueOf(serialNumber) + 1;
if (value > 99999999L) {
try {
Thread.sleep(1L);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
}
serialNumber = StringUtils.leftPad(value.toString(), 8, '0');
TIME_SELF_INCREASING_MAP.put(businessTypeTime, serialNumber);
return serialNumber;
}
/**
* 防止时间回拨
*
* @return
*/
private static Long newCurrentTime() throws Exception {
if (lastTime == null) {
//todo可以从redis获取最后一次系统时间
lastTime = System.currentTimeMillis();
}
long newCurrentTime = System.currentTimeMillis();
int tryTime = 0;
while (newCurrentTime < lastTime) {
try {
Thread.sleep(1L);
} catch (InterruptedException e) {
}
newCurrentTime = System.currentTimeMillis();
if (tryTime > MAX_TRY_TIME) {
throw new Exception("Time callback check error, the last time is:" + lastTime + "ms the time now is" + newCurrentTime + "ms");
} else {
tryTime++;
}
}
lastTime = newCurrentTime;
return newCurrentTime;
}
public static String generateOnlyID() {
return generateOnlyID(BASIC_BUSINESS);
}
/**
* 生成唯一键
* 首位+IP(12)+当前时间毫秒(10)+业务ID(6)+自增序列号(8)
* 1、当同一秒,同一个业务类型的自增序列号大于99999999L,等待1ms,重新生成
*
* @param businessType
* @return
*/
public static String generateOnlyID(String businessType) {
Long currentTime = null;
try {
currentTime = newCurrentTime();
} catch (Exception e) {
LOGGER.warn("businessType:{}", businessType, e);
return null;
}
businessType = Optional.ofNullable(businessType).orElse(BASIC_BUSINESS);
String selfIncreasingValue = selfIncreasing(businessType + currentTime);
if (selfIncreasingValue == null) {
return generateOnlyID(businessType);
}
return FIRST_INDEX + currentTime + IP + buildBusinessQueueId(businessType) + selfIncreasingValue;
}
public static void main(String[] args) {
long firstTime = System.currentTimeMillis();
for (int i = 0; i < 9999999L; i++) {
System.out.println(generateOnlyID("测试一下"));
}
long useTime = System.currentTimeMillis() - firstTime;
System.out.println("耗时:" + useTime + "ms");
System.out.println("平均耗时" + (useTime * 1000 / 9999999) + "us");
}
}
生成唯一键算法
猜你喜欢
转载自blog.csdn.net/xionglangs/article/details/116792366
今日推荐
周排行