Java生成唯一ID案例

wen java案例 8

本文目录导读:

Java生成唯一ID案例

  1. UUID(最常用)
  2. 基于时间戳 + 随机数
  3. 雪花算法(Snowflake)
  4. 使用第三方库(推荐)
  5. 综合封装工具类
  6. 性能对比
  7. 选择建议

我来为你介绍几种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长度限制等因素。

抱歉,评论功能暂时关闭!