Java集群环境下全局唯一流水ID生成方法之一

时间:2022-09-23 11:32:23
package com.pfq.deal.risk.util;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* 生成30位唯一数: yyyyMMddHHmmssSSS+服务器IP后5位+3位递增序号+5位随机数
* 如果将系统部署到集群上面,情况有会有不同了,不同的服务器集群生成的这个数字,是有重合的概率的,
* 因此,一般情况是,将集群中的每个机器进行IP编码,然后将机器编码放在这个标识中以示区分
*
* @author Dabria_ly 2017年8月24日
*/
public class Uidutil {
private static final Logger LOG = LoggerFactory.getLogger(Uidutil.class);
private static String no = "0";
private static String dateValue = "";//默认精确到毫秒的比对时间
private static Random rand = new Random();


public static synchronized String next() throws UnknownHostException {
String ipStr = InetAddress.getLocalHost().getHostAddress();// 获取本机IP
ipStr = ipStr.substring(ipStr.indexOf("." + 2)).replace(".", "");
if(ipStr.length() > 5){
ipStr = ipStr.substring(0, 5);
}
String dateStr = new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date());
String num = new StringBuilder().append(dateStr)
                       .append(ipStr).toString();
if (!(String.valueOf(dateStr)).equals(dateValue)) {//不是同一个时段,从0开始递增序号
no = "0";
dateValue = dateStr;
}
num += getNo(no, num);
return num;
}


/**
* 返回当前序号+1
*/
public static String getNo(String noCount, String num) {
long i = Long.parseLong(noCount);
i += 1;
noCount = "" + i;
for (int j = noCount.length(); j < 25 - num.length(); j++) {
noCount = "0" + noCount;
}
no = noCount;
return noCount;
}


/**
* 利用Set中不允许有重复的元素的特性,来判断集合元素中是否有重复元素

* @param list:被判断的集合
* @return false:有重复元素或list为null; true:没有重复元素
*/
private static boolean hasSame(List<? extends Object> list) {
if (null == list)
return false;
return list.size() == new HashSet<Object>(list).size();
}

/**
* next()+5位随机数
* @return
* @throws UnknownHostException
*/
public static String getTransactionId() throws UnknownHostException{
return new StringBuilder().append(next())
.append(String.valueOf(rand.nextInt(99999 - 10000 + 1) + 10000)).toString();
}


public static void main(String[] args) {
final List<String> guidList = new ArrayList<String>();
for (int i = 0; i < 10; i++) {// 开启10个线程
new Thread(new Runnable() {
@Override
public void run() {
for (int j = 0; j < 10000; j++) {// 每个线程循环1w条数据
try {
String guid = getTransactionId();
System.out.println("guid="+guid+",length="+guid.length());
guidList.add(guid);
} catch (UnknownHostException e) {
LOG.error("未知主机IP错误-->【{}】", e);
}
}


}


}).start();
}


try {
Thread.sleep(30000);// sleep 30秒
LOG.info("集合个数-->【{}】", guidList.size());
LOG.info("没有重复元素-->【{}】", hasSame(guidList));
} catch (InterruptedException e) {
LOG.error("sleep error-->【{}】", e);
}
}
}