Java生成32位全局唯一id

时间:2022-09-23 11:40:53

系统唯一ID是我们在设计一个系统的时候常常会遇见的问题,也常常为这个问题而纠结。生成ID的方法有很多,适应不同的场景、需求以及性能要求。这里说一下用java生成32位全局唯一id的实现过程。


主要实现思路是:14位的当前系统时间(格式为:yyyyMMddHHmmss) + 当前电脑的IP地址的最后两位 + 当前线程的hashCode的前9位 + 7位的随机数


一、相关实现代码

工具类实现代码如下:

package com.test;

import java.io.IOException;
import java.net.InetAddress;
import java.security.SecureRandom;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
import java.util.concurrent.atomic.AtomicLong;

import org.apache.commons.lang.StringUtils;

/**
* @ClassName: UniqId
* @Description: 生成32位全局唯一id
*/
public class UniqId {

private static UniqId me = new UniqId();
private String hostAddr;
private final Random random = new SecureRandom();
private final UniqTimer timer = new UniqTimer();

private boolean isOutputInfo = false;

private UniqId() {
try {
final InetAddress addr = InetAddress.getLocalHost();

hostAddr = addr.getHostAddress();
}
catch (final IOException e) {
System.err.println("[UniqID] Get HostAddr Error"+e);
hostAddr = String.valueOf(System.currentTimeMillis());
}

if (null == hostAddr || hostAddr.trim().length() == 0 || "127.0.0.1".equals(hostAddr)) {
hostAddr = String.valueOf(System.currentTimeMillis());

}
hostAddr = hostAddr.substring(hostAddr.length()-2).replace(".", "0");

if(isOutputInfo){
System.out.println("[UniqID]hostAddr is:" + hostAddr + "----length:"+hostAddr.length());
}
}


/**
* 获取UniqID实例
*
* @return UniqId
*/
public static UniqId getInstance() {
me.isOutputInfo = false;
return me;
}

/**
* 获取UniqID实例
*
* @return UniqId
*/
public static UniqId getInstanceWithLog() {
me.isOutputInfo = true;
return me;
}


/**
* 获得不会重复的毫秒数
*
* @return 不会重复的时间
*/
public String getUniqTime() {
String time = timer.getCurrentTime();
if(isOutputInfo){
System.out.println("[UniqID.getUniqTime]" + time +"----length:"+ time.length());
}
return time;
}

/**
* 获得UniqId
*
* @return uniqTime-randomNum-hostAddr-threadId
*/
public String getUniqID() {
final StringBuffer sb = new StringBuffer();
final String t = getUniqTime();
int randomNumber = random.nextInt(8999999) + 1000000;
sb.append(t);
sb.append(hostAddr);
sb.append(getUniqThreadCode());
sb.append(randomNumber);
if (isOutputInfo) {
System.out.println("[UniqID.randomNumber]" + randomNumber+"----length:"+String.valueOf(randomNumber).length());
System.out.println("[UniqID.getUniqID]" + sb.toString()+"----length:"+String.valueOf(sb).length());
}
return sb.toString();
}

public String getUniqThreadCode(){
String threadCode = StringUtils.left(String.valueOf(Thread.currentThread().hashCode()),9);
if (isOutputInfo) {
System.out.println("[UniqID.getUniqThreadCode]" +threadCode+"----length:"+threadCode.length());
}
return StringUtils.leftPad(threadCode, 9, "0");
}

/**
* 实现不重复的时间
*/
private class UniqTimer {
private final AtomicLong lastTime = new AtomicLong(System.currentTimeMillis());

public String getCurrentTime() {
if(!timestamp2Date(this.lastTime.incrementAndGet()).equals(timestamp2Date(System.currentTimeMillis()))){
lastTime.set(System.currentTimeMillis()+random.nextInt(10000));
}
return timestamp2Datetimes(this.lastTime.incrementAndGet());
}
}

/**
* 规范化日期,规范成yyyy-MM-dd
* @param timestamp
* @return
*/
public static String timestamp2Date(long timestamp){
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
return dateFormat.format(new Date(timestamp * 1000));
}

private static String timestamp2Datetimes(long timestamp){
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
return dateFormat.format(new Date(timestamp));
}

}


测试代码如下:

package com.test;

public class test {
public static void main(String[] args) {
//打印生成过程
UniqId.getInstanceWithLog().getUniqID();

//建议如下使用
// String uid = UniqId.getInstance().getUniqID();
// System.out.println(uid);
// System.out.println(uid.length());

}
}

二、jar包依赖

上述代码依赖org.apache.commons.lang.StringUtils,介绍如下两种依赖的方式:

方式一:Maven项目的依赖

如果你的项目是maven项目,那么请确保项目的pom.xml有如下依赖:

	<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.3</version>
</dependency>

方式二:普通java项目的引用

(1)如果你是一个普通的java工程,那么请将commons-lang-2.3.jar拷贝至你的工程,并添加到编译环境

(2)如果你是一个普通的javaWeb工程,那么直接将commons-lang-2.3.jar拷贝至工程的WEB-INF\lib下即可编译通过。

这里提供一下我个人的百度云存储commons-lang-2.3.jar的链接地址:

链接:https://pan.baidu.com/s/1c2qAx7y 密码:r9dr

当然你也可以从网上下载commons-lang的其他版本。