雪花实现思路

雪花算法是一种用于生成唯一标识符的分布式算法,由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();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

pilgrim786

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

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

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

打赏作者

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

抵扣说明:

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

余额充值