【在线OJ】雪花算法代码实现

雪花算法

用一个64比特位的long类型来作为生成id的类型,首先我们要了解哪些位置对应的意义,其中在本项目中10位的工作机器id被细分位5bit的机房id与5bit的机器id。雪花算法支持每毫秒生成2的12次方-1个id。

用一个64比特位的long类型来作为生成id的类型,首先我们要了解哪些位置对应的意义,其中在本项目中10位的工作机器id被细分位5bit的机房id与5bit的机器id。雪花算法支持每毫秒生成2的12次方-1个id。

视频

External Player - 哔哩哔哩嵌入式外链播放器

实现思路

在实现时首先需要准备一些必须的字段,我们需要记录一个初始的时间戳这个时间戳不能修改,最好使用部署时间或者开发当前时间,其次我们要记录时间戳、机房id、机器id、序列化分别占多少位,然后我们还有记录机器码与机房码等

在实现时,首先我们要获取当前的时间戳,如果当前时间戳比上一次获取时,如果比上一次小说明这是一次非法调用抛出异常,如果等于上一次的时间戳说明这是同一毫秒,我们需要让序列化+1,但 同时我们需要判断序列化+1以后是否到达该毫秒内能生成的最大id如果等于了则获取下一毫秒的时间。如果当前时间戳大于上一次调用时的时间戳,说明是另外的一毫秒于是序列化重置为0,最好根据上述图中规则进行组装后返回

代码实现
package com.cloud.cloud_oj_common.utils;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: PG
 * Date: 2024-04-17
 * Time: 19:11
 */

/**
 * 雪花算法
 */
public class SnowFlake {
    private static final long START_TIME = 1609459200000L; // 设置起始时间戳
    private static final long SEQUENCE_BIT = 12L;  // 设置序列号所占比特位
    private static final long MACHINE_BIT = 5L;   // 设置机器码所占比特位
    private static final long DATACENTER_BIT = 5L;// 设置机房码所占比特位
    private static final long MAX_MACHINE_NUM = ~(-1L << MACHINE_BIT);  // 机器码最大值
    private static final long MAX_DATACENTER_NUM = ~(-1L << DATACENTER_BIT); // 机房码最大值
    private static final long MAX_SEQUENCE_NUM = ~(-1L << SEQUENCE_BIT); // 序列号最大值,1毫秒能生成的最多id数
    private static long machineId;  // 机器码
    private static long datacenterId; // 机房码
    private static long sequence = 0L;       // 序列号
    private static long lastTimestamp = -1L; // 上一次时间戳

    /**
     * 配置机器码与机房码
     * @param machine 机器码
     * @param datacenter 机房码
     */
    public static void setConfig(long machine, long datacenter) {
        if (machine >= MAX_MACHINE_NUM || datacenter >= MAX_DATACENTER_NUM) {
            throw new RuntimeException("机器码异常");
        }
        machineId = machine;
        datacenterId = datacenter;
    }

    /**
     * 获取下一个id
     * @return
     */
    public static synchronized long generateId() {
        long timestamp = System.currentTimeMillis(); // 获取当前时间戳

        if (timestamp < lastTimestamp) {            // 如果比上一次小则说明是异常
            throw new RuntimeException("时间戳错误");
        }

        if (timestamp == lastTimestamp) {          // 如果与上一次相同,则说明是需要同一毫秒生成的
            sequence = (sequence + 1) & MAX_SEQUENCE_NUM;  // 让序列化加1以后与序列化的最大值,如果是最大值那么结果就是0,如果不是最大值结果就是原序列号+1
            if (sequence == 0) {    // 说明当前毫秒内id生成以及达到上限
                timestamp = tilNextMillis(lastTimestamp); // 获取下一毫秒即可
            }
        } else {   // 如果当前时间戳大于上一次时间戳说明是新的1毫秒,序列化置为0即可
            sequence = 0L;
        }

        lastTimestamp = timestamp;  // 修改记录上一次调用的时间戳
        return (timestamp - START_TIME) << (SEQUENCE_BIT + MACHINE_BIT + DATACENTER_BIT)  // 将时间戳左移到合适位置
        | datacenterId << (SEQUENCE_BIT + MACHINE_BIT) // 将机房码左移合适的位置
        | machineId << (SEQUENCE_BIT) 
        | sequence;
    }

    /**
     * 获取下一毫秒的时间戳
     * @param lastTimestamp 上一毫秒
     * @return 下一毫秒
     */
    private static long tilNextMillis(long lastTimestamp) {
        long timestamp = System.currentTimeMillis();
        while (timestamp <= lastTimestamp) {
            timestamp = System.currentTimeMillis();
        }
        return timestamp;
    }
}
  • 7
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

1886i

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值