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();
    }
}
相关推荐
AMiner:AI科研助手18 小时前
警惕!你和ChatGPT的对话,可能正在制造分布式妄想
人工智能·分布式·算法·chatgpt·deepseek
CHANG_THE_WORLD21 小时前
并发编程指南 同步操作与强制排序
开发语言·c++·算法
gaoshou451 天前
代码随想录训练营第三十一天|LeetCode56.合并区间、LeetCode738.单调递增的数字
数据结构·算法
自信的小螺丝钉1 天前
Leetcode 240. 搜索二维矩阵 II 矩阵 / 二分
算法·leetcode·矩阵
KING BOB!!!1 天前
Leetcode高频 SQL 50 题(基础版)题目记录
sql·mysql·算法·leetcode
我是渣哥1 天前
Java String vs StringBuilder vs StringBuffer:一个性能优化的探险故事
java·开发语言·jvm·后端·算法·职场和发展·性能优化
THMAIL1 天前
机器学习从入门到精通 - 机器学习调参终极手册:网格搜索、贝叶斯优化实战
人工智能·python·算法·机器学习·支持向量机·数据挖掘·逻辑回归
lytk991 天前
矩阵中寻找好子矩阵
线性代数·算法·矩阵
珊瑚怪人1 天前
算法随笔(一)
算法
晚安里1 天前
JVM相关 4|JVM调优与常见参数(如 -Xms、-Xmx、-XX:+PrintGCDetails) 的必会知识点汇总
java·开发语言·jvm·后端·算法