Twitter Snowflake算法的分布式唯一ID生成器

Snowflake算法是一种在分布式系统中生成全局唯一ID的算法,它保证了生成的ID是趋势递增的,这对于数据库中的索引友好,并且生成效率高。以下是我根据自己需求写的ID生成器工具类。

/**
 * 基于Twitter Snowflake算法的分布式唯一ID生成器工具类。
 */
public class SnowflakeIdGeneratorUtils {
    
    // 开始时间戳 (2020-01-01)
    /** 开始时间戳,用于计算时间部分的偏移量。 */
    private static final long START_TIMESTAMP = 1577836800000L;

    // 每一部分占用的位数
    /** 序列号占用的位数,用于在同一毫秒内生成多个ID。 */
    private static final long SEQUENCE_BITS = 12;
    /** 机器标识占用的位数,用于区分不同的机器。 */
    private static final long MACHINE_BITS = 5;
    /** 数据中心占用的位数,用于区分不同的数据中心。 */
    private static final long DATACENTER_BITS = 5;

    // 每一部分的最大值
    /** 序列号的最大值。 */
    private static final long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BITS);
    /** 机器标识的最大值。 */
    private static final long MAX_MACHINE = -1L ^ (-1L << MACHINE_BITS);
    /** 数据中心标识的最大值。 */
    private static final long MAX_DATACENTER = -1L ^ (-1L << DATACENTER_BITS);

    // 每一部分向左的位移
    /** 机器标识向左的位移量。 */
    private static final long MACHINE_SHIFT = SEQUENCE_BITS;
    /** 数据中心标识向左的位移量。 */
    private static final long DATACENTER_SHIFT = SEQUENCE_BITS + MACHINE_BITS;
    /** 时间戳向左的位移量。 */
    private static final long TIMESTAMP_SHIFT = DATACENTER_SHIFT + DATACENTER_BITS;

    // 成员变量
    /** 数据中心ID。 */
    private long datacenterId;
    /** 机器ID。 */
    private long machineId;
    /** 序列号,用于在同一毫秒内生成多个ID。 */
    private long sequence = 0L;
    /** 上一次生成ID的时间戳。 */
    private long lastTimestamp = -1L;

    /**
     * 构造函数,初始化数据中心ID和机器ID。
     *
     * @param datacenterId 数据中心ID
     * @param machineId    机器ID
     */
    public SnowflakeIdGeneratorUtils(long datacenterId, long machineId) {
        // 校验数据中心ID和机器ID是否在合法范围内
        if (datacenterId > MAX_DATACENTER || datacenterId < 0) {
            throw new IllegalArgumentException("Datacenter ID can't be greater than " + MAX_DATACENTER + " or less than 0");
        }
        if (machineId > MAX_MACHINE || machineId < 0) {
            throw new IllegalArgumentException("Machine ID can't be greater than " + MAX_MACHINE + " or less than 0");
        }
        this.datacenterId = datacenterId;
        this.machineId = machineId;
    }

    /**
     * 生成下一个ID。
     *
     * @return 下一个唯一ID
     */
    public synchronized long nextId() {
        long currentTimestamp = System.currentTimeMillis();

        // 如果当前时间小于上一次生成ID的时间,抛出异常(时钟回拨)
        if (currentTimestamp < lastTimestamp) {
            throw new RuntimeException("Clock moved backwards. Refusing to generate id");
        }

        // 如果当前时间与上一次生成ID的时间相同,则序列号加1
        if (currentTimestamp == lastTimestamp) {
            sequence = (sequence + 1) & MAX_SEQUENCE;
            // 如果序列号达到最大值,则等待下一毫秒
            if (sequence == 0) {
                currentTimestamp = getNextMillisecond(lastTimestamp);
            }
        } else {
            // 如果当前时间大于上一次生成ID的时间,重置序列号
            sequence = 0L;
        }

        // 更新上一次生成ID的时间戳
        lastTimestamp = currentTimestamp;

        // 组合时间戳、数据中心ID、机器ID和序列号生成ID
        return ((currentTimestamp - START_TIMESTAMP) << TIMESTAMP_SHIFT)
                | (datacenterId << DATACENTER_SHIFT)
                | (machineId << MACHINE_SHIFT)
                | sequence;
    }

    /**
     * 等待直到下一毫秒。
     *
     * @param lastTimestamp 上一次生成ID的时间戳
     * @return 下一毫秒的时间戳
     */
    private long getNextMillisecond(long lastTimestamp) {
        long timestamp = System.currentTimeMillis();
        // 循环等待直到时间戳大于上一次生成ID的时间戳
        while (timestamp <= lastTimestamp) {
            timestamp = System.currentTimeMillis();
        }
        return timestamp;
    }

    /**
     * 生成订单号。
     *
     * @return 订单号字符串(最多32位)
     */
    public String generateOrderNumber() {
        long id = nextId();
        String orderNumber = String.valueOf(id);
        // 如果订单号长度超过32位,则截取前32位
        if (orderNumber.length() > 32) {
            orderNumber = orderNumber.substring(0, 32);
        }
        return orderNumber;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值