All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.biz.common.id.SnowflakeGenerator Maven / Gradle / Ivy

There is a newer version: 1.5.1
Show newest version
package com.biz.common.id;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 雪花ID生成器,用于生成全局唯一且递增的ID。
 * 使用Snowflake算法,基于时间戳、机器ID和序列号生成ID。
 *
 * @author francis
 * @create 2023-07-09 09:49
 **/
public class SnowflakeGenerator {

    // 基准时间戳,即2021年1月1日0点,用于计算相对于此时间的毫秒数
    private static final long EPOCH = 1609459200000L;
    // 序列号占用的位数
    private static final int SEQUENCE_BITS = 12;
    // 机器ID占用的位数
    private static final int MACHINE_ID_BITS = 10;
    // 序列号的最大值
    private static final int MAX_SEQUENCE = (1 << SEQUENCE_BITS) - 1;
    // 机器ID的最大值
    private static final int MAX_MACHINE_ID = (1 << MACHINE_ID_BITS) - 1;

    // 基于基准时间的偏移量
    private final long twepoch = EPOCH;
    // 机器ID,用于区分不同的生成器实例
    private final int machineId;
    // 用于同步生成ID的锁
    private final Lock lock = new ReentrantLock();

    // 上次生成ID的时间戳
    private volatile long lastTimestamp = -1L;
    // 当前序列号
    private volatile int sequence = 0;

    /**
     * 默认机器ID,用于没有指定机器ID的情况
     */
    public static final int DEFAULT_MACHINE_ID = 0;

    /**
     * 构造函数,初始化SnowflakeGenerator。
     *
     * @param machineId 机器ID,用于区分不同的生成器实例。
     *                  必须在0到MAX_MACHINE_ID之间。
     */
    public SnowflakeGenerator(int machineId) {
        if (isMachineIdNotValid(machineId)) {
            throw new IllegalArgumentException("Invalid machine ID");
        }
        this.machineId = machineId;
    }

    /**
     * 生成全局唯一的ID。
     *
     * @return 生成的唯一ID。
     */
    public long generate() {
        lock.lock();
        try {
            long timestamp = System.currentTimeMillis();

            // 处理系统时间回拨的情况
            if (timestamp < lastTimestamp) {
                handleClockBackward(lastTimestamp);
            }

            // 当时间戳与上一次相同,递增序列号
            if (timestamp == lastTimestamp) {
                sequence = (sequence + 1) & MAX_SEQUENCE;
                // 如果序列号溢出,则等待下一个时间戳
                if (sequence == 0) {
                    timestamp = waitForNextMillis(lastTimestamp);
                }
            } else {
                // 重置序列号
                sequence = 0;
            }

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

            // 构造ID:时间戳部分、机器ID部分和序列号部分
            return ((timestamp - twepoch) << (MACHINE_ID_BITS + SEQUENCE_BITS)) |
                    ((long) machineId << SEQUENCE_BITS) |
                    sequence;
        } finally {
            lock.unlock();
        }
    }

    /**
     * 检查机器ID是否不合法。
     *
     * @param machineId 机器ID
     * @return 机器ID是否不合法
     */
    public static boolean isMachineIdNotValid(int machineId) {
        return machineId < 0 || machineId > MAX_MACHINE_ID;
    }

    /**
     * 处理系统时间回拨的情况,抛出异常拒绝生成ID。
     *
     * @param lastTimestamp 上次生成ID的时间戳
     */
    private void handleClockBackward(long lastTimestamp) {
        throw new RuntimeException(String.format("Clock moved backward. Refusing to generate id for timestamp %d while last timestamp was %d",
                System.currentTimeMillis(), lastTimestamp));
    }

    /**
     * 等待直到下一个毫秒,避免系统时间回拨导致的问题。
     *
     * @param lastTimestamp 上次生成ID的时间戳
     * @return 等待后的当前时间戳
     */
    private long waitForNextMillis(long lastTimestamp) {
        long timestamp = System.currentTimeMillis();
        while (timestamp <= lastTimestamp) {
            timestamp = System.currentTimeMillis();
        }
        return timestamp;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy