Require:基于雪花算法完成一个局部随机,全局离散没有热点切唯一的数值Id生成器。

**【雪花算法】**雪花算法(Snowflake Algorithm)是Twitter开源的用于生成唯一ID的算法,它可以在分布式系统中生成唯一的64位长整数ID。这种ID生成方式既保证了趋势递增,又保证了在不同数据中心、不同机器上生成的ID的唯一性。

  • **符号位:**占用1位。

  • 时间戳:通常占用41位,表示从某个固定时间点(如1970年1月1日)起的毫秒数。这使得生成的ID具有时间排序性。

  • 机器ID:占用10位,表示生成ID的机器节点,以确保不同机器生成的ID不冲突。

  • 序列号:占用12位,允许同一毫秒内生成多个ID,通常用于支持高并发。

    public class SnowflakeIdGenerator {
    private static final long EPOCH = 1640995200000L; // 自定义的开始时间戳(2022年1月1日)
    private static final long MACHINE_ID_BITS = 10L; // 机器ID的位数
    private static final long SEQUENCE_BITS = 12L; // 序列号的位数

    复制代码
      private static final long MAX_MACHINE_ID = ~(-1L << MACHINE_ID_BITS); // 机器ID最大值
      private static final long SEQUENCE_MASK = ~(-1L << SEQUENCE_BITS); // 序列号最大值
    
      private long machineId; // 当前机器ID
      private long sequence = 0L; // 当前序列号
      private long lastTimestamp = -1L; // 上次生成ID的时间戳
    
      public SnowflakeIdGenerator(long machineId) {
          if (machineId > MAX_MACHINE_ID || machineId < 0) {
              throw new IllegalArgumentException("Machine ID can't be greater than " + MAX_MACHINE_ID + " or less than 0");
          }
          this.machineId = machineId;
      }
    
      public synchronized long generateId() {
          long timestamp = System.currentTimeMillis();
    
          // 如果当前时间小于上次生成ID的时间戳,说明系统时钟回拨,抛出异常
          if (timestamp < lastTimestamp) {
              throw new RuntimeException("Clock is moving backwards. Rejecting requests until " + lastTimestamp);
          }
    
          // 如果在同一毫秒内,增加序列号
          if (lastTimestamp == timestamp) {
              sequence = (sequence + 1) & SEQUENCE_MASK; // 使用位运算确保序列号循环
              // 如果序列号溢出,等待下一毫秒
              if (sequence == 0) {
                  timestamp = waitForNextMillis(lastTimestamp);
              }
          } else {
              sequence = 0L; // 如果是新的毫秒,重置序列号
          }
    
          lastTimestamp = timestamp; // 更新上次生成ID的时间戳
    
          // 组合ID
          return ((timestamp - EPOCH) << (MACHINE_ID_BITS + SEQUENCE_BITS)) | (machineId << SEQUENCE_BITS) | sequence;
      }
    
      private long waitForNextMillis(long lastTimestamp) {
          long timestamp = System.currentTimeMillis();
          while (timestamp <= lastTimestamp) {
              timestamp = System.currentTimeMillis(); // 等待下一毫秒
          }
          return timestamp;
      }

    }

【雪花算法-修正版】

复制代码
/*
 * Long: 1,000,000,000,000,000,000-9,223,372,036,854,775,807,共19位
 * 雪花算法变种实现: {HHmmssSSS-9位}+{系统号-2位}+{毫秒递增seq-4位}+{随机数-3位}
 * */
public class TiDBRandomPrimaryKeyGenerator {

    //机器号
    private String machineId;
    public static AtomicInteger machineIndex = new AtomicInteger(0);
    //序列号
    private long sequence = 0L;
    //上一个时间戳,用于保证同一毫秒内序列号不重复。
    private long lastTimestamp = -1L;
    //序列号最大值
    private static final long SEQUENCE_MASK = 9999;

    private String pattern = "HHmmssSSS";

    public TiDBRandomPrimaryKeyGenerator() {
        machineId = getInerMachineId();
        this.sequence = (long) (Math.random() * SEQUENCE_MASK);
    }

    public synchronized long nextId() {
        Date currentDate = new Date();
        String dateTime = DateFormatUtils.format(currentDate, pattern);
        String seq = getInerSequence(currentDate.getTime());
        String random = generateRandomString(3);
        StringBuilder id = new StringBuilder(32);
        id.append(dateTime).append(machineId).append(seq).append(random);
        return Long.parseLong(String.valueOf(id));
    }

    private synchronized String getInerSequence(long timestamp) {
        if (timestamp < lastTimestamp) {
            throw new RuntimeException("Clock moved backwards. Refusing to generate id for " + (lastTimestamp - timestamp) + " milliseconds");
        }
        // 如果是同一毫秒内的时间戳
        if (lastTimestamp == timestamp) {
            sequence = (sequence + 1) % SEQUENCE_MASK;
        } else {
            sequence = 0;
        }
        lastTimestamp = timestamp;
        return String.format("%04d", sequence);
    }

    private String getInerMachineId( ) {
        String machineId = String.format("%02d", machineIndex.intValue());
        this.machineIndex.incrementAndGet();
        return machineId;
    }

    public static String generateRandomString(int length) {
        Random random = new Random();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < length; i++) {
            // 生成0到9之间的随机数,并转换为字符
            char randomChar = (char) (random.nextInt(10) + '0');
            sb.append(randomChar);
        }
        return sb.toString();
    }
}
相关推荐
江畔柳前堤12 小时前
大语言模型分布式训练:从并行策略到万卡工程的系统梳理
人工智能·分布式·深度学习·算法·目标检测·机器学习·语言模型
Forever Nore13 小时前
LeetCode 4 寻找两个正序数组的中位数 - 二分
算法·leetcode
罗西的思考14 小时前
【OpenClaw具身硬件】MiniClaw 阅读笔记---(1)基础
人工智能·算法·机器学习
蛋先生DX15 小时前
大模型参数存储格式揭秘:BF不是男朋友
深度学习·算法·llm
爱跳舞的烤冷面16 小时前
自学嵌入式第22天(数据结构——哈希)
数据结构·算法·哈希算法
猎嘤一号16 小时前
博弈论(Game Theory)的理论、算法与工程
人工智能·算法·安全·博弈论
月光船幽幽16 小时前
影子模式下保护 logits 不被修改
人工智能·python·算法
马拉AI16 小时前
腾讯开源 Agent 记忆系统,AI“换对话就忘”的问题有了新解法(附安装使用教程)
人工智能·算法·开源·科研
地平线开发者18 小时前
征程6工具链模型X86推理方式说明
算法
地平线开发者18 小时前
【征程6】校准量化中HistogramObserver解析
算法