雪花实现思路

雪花算法是一种用于生成唯一标识符的分布式算法,由Twitter设计开发。它的核心思想是利用时间戳、机器ID和序列号来生成全局唯一的64位整数。下面是一个简化版的雪花算法的描述:

雪花算法的构成:

  • 64位整数: 雪花算法生成的ID是一个64位的整数,它由以下几部分组成:
    • 1位符号位(始终为0) + 41位时间戳 + 10位机器ID + 12位序列号。

具体构成:

  1. 时间戳(41位):

    • 使用当前时间戳,精确到毫秒级别。
    • 41位时间戳可以支持约 69 年的时间。
  2. 机器ID(10位):

    • 标识不同的机器节点,确保在不同节点上生成的ID不会冲突。
    • 通常由数据中心ID和机器ID组成。
  3. 序列号(12位):

    • 为了解决同一毫秒内可能出现的多次ID生成需求而设计。
    • 当在同一毫秒内生成多个ID时,使用序列号来区分,确保生成的ID唯一。

工作流程:

  1. 获取时间戳: 获取当前时间戳,以毫秒为单位。

  2. 判断时钟回拨:

    • 如果检测到时钟回拨,则暂停生成,直到时钟追上之前的时间戳,避免重复和混乱。
  3. 生成ID:

    • 将时间戳左移22位(64-41位)腾出空间给机器ID和序列号。
    • 将机器ID左移12位(64-41-10位),与时间戳相加。
    • 将序列号加到最低位的12位。

注意事项:

  • 机器ID唯一性: 不同机器的ID必须唯一,避免冲突。
  • 时钟同步: 时间戳的连续性和准确性对于ID的唯一性至关重要。

这种算法的设计目的是在分布式系统中生成唯一的ID,适用于高并发、分布式的场景,并且不依赖于中心化的ID分配服务。

实现思路

public class Snowflake {
    private final long workerId;
    private long sequence = 0L;
    private final long twepoch = 1620079244226L; // 起始时间戳,可以设置一个合适的开始时间

    private final long workerIdBits = 5L; // 机器 ID 的位数
    private final long maxWorkerId = -1L ^ (-1L << workerIdBits); // 最大机器 ID
    private final long sequenceBits = 12L; // 序列号的位数
    private final long workerIdShift = sequenceBits; 
    private final long timestampLeftShift = sequenceBits + workerIdBits;
    private final long sequenceMask = -1L ^ (-1L << sequenceBits);

    private long lastTimestamp = -1L;

    public Snowflake(long workerId) {
        if (workerId > maxWorkerId || workerId < 0) {
            throw new IllegalArgumentException("Worker ID 必须在 0 到 " + maxWorkerId + " 之间");
        }
        this.workerId = workerId;
    }

    public synchronized long nextId() {
        long timestamp = timeGen();

        if (timestamp < lastTimestamp) {
            throw new RuntimeException("时钟向后移动,拒绝生成ID");
        }

        if (timestamp == lastTimestamp) {
            sequence = (sequence + 1) & sequenceMask;
            if (sequence == 0) {
                timestamp = tilNextMillis(lastTimestamp);
            }
        } else {
            sequence = 0;
        }

        lastTimestamp = timestamp;

        return ((timestamp - twepoch) << timestampLeftShift) |
                (workerId << workerIdShift) |
                sequence;
    }

    private long tilNextMillis(long lastTimestamp) {
        long timestamp = timeGen();
        while (timestamp <= lastTimestamp) {
            timestamp = timeGen();
        }
        return timestamp;
    }

    private long timeGen() {
        return System.currentTimeMillis();
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
你好,关于Java雪花算法的具体实现,我可以给你提供一些参考。大概思路是使用机器当前时间和一个ID号生成唯一的订单号。下面是Java代码实现: ```java public class SnowflakeIdGenerator { private static final long START_STMP = 1480166465631L; // 起始时间戳,用于减少数字的位数 private static final long MACHINE_ID_BITS = 5L; // 机器标识位数 private static final long DATACENTER_ID_BITS = 5L; // 数据中心标识位数 private static final long SEQUENCE_BITS = 12L; // 序列号位数 private static final long MAX_MACHINE_ID = ~(-1L << MACHINE_ID_BITS); // 最大机器标识数 private static final long MAX_DATACENTER_ID = ~(-1L << DATACENTER_ID_BITS); // 最大数据中心标识数 private static final long MACHINE_ID_LEFT_SHIFT_BITS = SEQUENCE_BITS; // 机器标识左移位数 private static final long DATACENTER_ID_LEFT_SHIFT_BITS = SEQUENCE_BITS + MACHINE_ID_BITS; // 数据中心标识左移位数 private static final long TIMESTAMP_LEFT_SHIFT_BITS = SEQUENCE_BITS + MACHINE_ID_BITS + DATACENTER_ID_BITS; // 时间戳左移位数 private final long machineId; // 机器标识 private final long datacenterId; // 数据中心标识 private long sequence = 0L; // 序列号 private long lastStmp = -1L; // 上一次计算的时间戳 public SnowflakeIdGenerator(long machineId, long datacenterId) { if (machineId > MAX_MACHINE_ID || machineId < 0) { throw new IllegalArgumentException(String.format("Machine Id can't be greater than %d or less than 0", MAX_MACHINE_ID)); } if (datacenterId > MAX_DATACENTER_ID || datacenterId < 0) { throw new IllegalArgumentException(String.format("Datacenter Id can't be greater than %d or less than 0", MAX_DATACENTER_ID)); } this.machineId = machineId; this.datacenterId = datacenterId; } public synchronized long nextId() { long currStmp = getNewstmp(); if (currStmp < lastStmp) { throw new RuntimeException("Clock moved backwards. Refusing to generate id"); } if (currStmp == lastStmp) { sequence = (sequence + 1) & ~(-1L << SEQUENCE_BITS); if (sequence == 0L) { currStmp = getNextMill(); } } else { sequence = 0L; } lastStmp = currStmp; return (currStmp - START_STMP) << TIMESTAMP_LEFT_SHIFT_BITS // 左移时间戳 | datacenterId << DATACENTER_ID_LEFT_SHIFT_BITS // 左移数据中心标识 | machineId << MACHINE_ID_LEFT_SHIFT_BITS // 左移机器标识 | sequence; // 序列号 } private long getNextMill() { long mill = getNewstmp(); while (mill <= lastStmp) { mill = getNewstmp(); } return mill; } private long getNewstmp() { return System.currentTimeMillis(); } } ``` 这个算法会生成一个Long类型的订单号,具体看需要和业务场景使用。当然您也可以根据具体需求做出适当的修改。希望对您有所帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

pilgrim786

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

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

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

打赏作者

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

抵扣说明:

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

余额充值