本文目录导读:

我来为你介绍几种Java生成唯一ID的常用方案,从简单到复杂,各有适用场景。
UUID(最常用)
import java.util.UUID;
public class UUIDExample {
public static void main(String[] args) {
// 标准UUID格式
String uuid = UUID.randomUUID().toString();
System.out.println("标准UUID: " + uuid);
// 输出: 550e8400-e29b-41d4-a716-446655440000
// 去掉横线
String uuidWithoutDash = UUID.randomUUID().toString().replace("-", "");
System.out.println("无横线UUID: " + uuidWithoutDash);
// 输出: 550e8400e29b41d4a716446655440000
}
}
基于时间戳 + 随机数
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
public class TimestampIDGenerator {
private static final AtomicInteger SEQUENCE = new AtomicInteger(0);
private static final Random RANDOM = new Random();
// 方法1:时间戳 + 随机数
public static String generateByTimestamp() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
String timestamp = sdf.format(new Date());
int randomNum = RANDOM.nextInt(9999);
return timestamp + String.format("%04d", randomNum);
}
// 方法2:时间戳 + 序列号(保证并发安全)
public static String generateBySequence() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
String timestamp = sdf.format(new Date());
int sequence = SEQUENCE.incrementAndGet() % 10000;
return timestamp + String.format("%04d", sequence);
}
public static void main(String[] args) {
System.out.println("时间戳+随机数: " + generateByTimestamp());
System.out.println("时间戳+序列号: " + generateBySequence());
}
}
雪花算法(Snowflake)
public class SnowflakeIdGenerator {
// 各部分位数
private final long workerIdBits = 5L;
private final long datacenterIdBits = 5L;
private final long sequenceBits = 12L;
// 最大值
private final long maxWorkerId = -1L ^ (-1L << workerIdBits);
private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
// 位移
private final long workerIdShift = sequenceBits;
private final long datacenterIdShift = sequenceBits + workerIdBits;
private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
// 掩码
private final long sequenceMask = -1L ^ (-1L << sequenceBits);
private long workerId;
private long datacenterId;
private long sequence = 0L;
private long lastTimestamp = -1L;
public SnowflakeIdGenerator(long workerId, long datacenterId) {
if (workerId > maxWorkerId || workerId < 0) {
throw new IllegalArgumentException("workerId 超出范围");
}
if (datacenterId > maxDatacenterId || datacenterId < 0) {
throw new IllegalArgumentException("datacenterId 超出范围");
}
this.workerId = workerId;
this.datacenterId = datacenterId;
}
public synchronized long nextId() {
long timestamp = System.currentTimeMillis();
if (timestamp < lastTimestamp) {
throw new RuntimeException("时钟回拨问题");
}
if (timestamp == lastTimestamp) {
sequence = (sequence + 1) & sequenceMask;
if (sequence == 0) {
timestamp = tilNextMillis(lastTimestamp);
}
} else {
sequence = 0L;
}
lastTimestamp = timestamp;
return ((timestamp - 1288834974657L) << timestampLeftShift) |
(datacenterId << datacenterIdShift) |
(workerId << workerIdShift) |
sequence;
}
private long tilNextMillis(long lastTimestamp) {
long timestamp = System.currentTimeMillis();
while (timestamp <= lastTimestamp) {
timestamp = System.currentTimeMillis();
}
return timestamp;
}
public static void main(String[] args) {
SnowflakeIdGenerator generator = new SnowflakeIdGenerator(1, 1);
for (int i = 0; i < 10; i++) {
System.out.println("雪花ID: " + generator.nextId());
}
}
}
使用第三方库(推荐)
Hutool工具类
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
public class HutoolIDGenerator {
public static void main(String[] args) {
// 简单UUID
String uuid = IdUtil.simpleUUID();
System.out.println("简易UUID: " + uuid);
// 雪花算法
Snowflake snowflake = IdUtil.getSnowflake(1, 1);
long id = snowflake.nextId();
System.out.println("Hutool雪花ID: " + id);
// 生成ID字符串
String snowflakeId = IdUtil.getSnowflakeNextIdStr();
System.out.println("雪花ID字符串: " + snowflakeId);
}
}
需要添加依赖
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-captcha</artifactId>
<version>5.8.16</version>
</dependency>
综合封装工具类
import java.util.UUID;
import java.util.concurrent.atomic.AtomicLong;
public class OrderNumberGenerator {
private static final AtomicLong SEQ = new AtomicLong(0);
// 生成订单号:时间戳 + 用户ID + 随机数
public static String generateOrderNo(String userId) {
StringBuilder sb = new StringBuilder();
// 1. 时间部分(14位)
sb.append(String.format("%tY%<tm%<td%<tH%<tM%<tS", System.currentTimeMillis()));
// 2. 用户ID的一部分
if (userId != null && userId.length() >= 4) {
sb.append(userId.substring(Math.max(0, userId.length() - 4)));
} else {
sb.append("0000");
}
// 3. 序列号(4位)
long seq = SEQ.incrementAndGet() % 10000;
sb.append(String.format("%04d", seq));
return sb.toString();
}
// 生成纯数字ID
public static long generateNumericId() {
return System.currentTimeMillis() * 1000 + SEQ.incrementAndGet() % 1000;
}
public static void main(String[] args) {
// 测试
for (int i = 0; i < 5; i++) {
System.out.println("订单号: " + generateOrderNo("U1234567"));
System.out.println("数字ID: " + generateNumericId());
System.out.println("---");
}
}
}
性能对比
import java.util.UUID;
import java.util.concurrent.ConcurrentSkipListSet;
public class PerformanceTest {
public static void main(String[] args) throws Exception {
int count = 10000;
// UUID性能测试
long start = System.currentTimeMillis();
ConcurrentSkipListSet<String> uuidSet = new ConcurrentSkipListSet<>();
for (int i = 0; i < count; i++) {
uuidSet.add(UUID.randomUUID().toString());
}
long uuidTime = System.currentTimeMillis() - start;
System.out.println("UUID生成 " + count + " 个,耗时: " + uuidTime + "ms");
// 雪花算法性能测试
SnowflakeIdGenerator snowflake = new SnowflakeIdGenerator(1, 1);
start = System.currentTimeMillis();
ConcurrentSkipListSet<Long> snowflakeSet = new ConcurrentSkipListSet<>();
for (int i = 0; i < count; i++) {
snowflakeSet.add(snowflake.nextId());
}
long snowflakeTime = System.currentTimeMillis() - start;
System.out.println("雪花算法生成 " + count + " 个,耗时: " + snowflakeTime + "ms");
// 检查是否有重复
System.out.println("UUID重复数量: " + (count - uuidSet.size()));
System.out.println("雪花ID重复数量: " + (count - snowflakeSet.size()));
}
}
选择建议
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| UUID | 简单、无依赖、全球唯一 | 36位过长、无序 | 数据库主键、文件名 |
| 时间戳+随机数 | 简单、短 | 可能重复 | 订单号 |
| 雪花算法 | 有序、高性能、趋势递增 | 依赖系统时间 | 高并发系统 |
| Hutool | 封装完善、功能多 | 需要添加依赖 | 生产环境 |
推荐:
- 简单应用用 UUID
- 分布式系统用 雪花算法
- 业务订单号用 时间戳+业务前缀+随机数
选择时考虑:唯一性要求、性能要求、是否分布式、是否需要趋势递增、ID长度限制等因素。