手写雪花算法

需求:我们需要给请求一个唯一标识,用来标识一个请求和响应的关联关系,我们要求请求的id必须唯 一,且不能占用过大的空间

分析:1、uuid,但uuid作为唯一标识占用空间太大(16字节) 2、使用雪花算法(8字节)

构思:

 代码实现:

package com.example.utils;

import java.util.concurrent.atomic.LongAdder;

/**
 * @Description: 手写雪花算法 生成请求id
 * @ClassName: IdGenerator
 * @Author: dianZiMuYu
 * @Date: 2023/7/31 15:43
 */
public class IdGenerator {

    public static final long START_STAMP = DateUtil.get("2021-11-26").getTime();
    public static final long DATA_CENTER_BIT = 5L;
    public static final long MACHINE_BIT = 5L;
    public static final long SEQUENCE_BIT = 12L;

    /**
     * 移位操作 提高速度
     *
     */
    public static final long DATA_CENTER_MAX = ~(-1L << DATA_CENTER_BIT);
    public static final long MACHINE_MAX = ~(-1L << MACHINE_BIT);
    public static final long SEQUENCE_MAX = ~(-1L << SEQUENCE_BIT);
    /**
     * 移位 + 或操作
     * 时间戳 (42) 机房号 (5) 机器号 (5) 序列号 (12)
     */
    public static final long TIMESTAMP_LEFT_OFFSET = DATA_CENTER_BIT + MACHINE_BIT + SEQUENCE_BIT;
    public static final long DATA_CENTER_LEFT_OFFSET = MACHINE_BIT + SEQUENCE_BIT;
    public static final long MACHINE_LEFT_OFFSET = SEQUENCE_BIT;

    /**
     * 属性
     */
    private long dataCenterId;
    private long machineId;
    /**
     * JDK1.8新增的一个原子性操作类
     */
    private LongAdder sequenceId = new LongAdder();
    private long lastTimeStamp = -1L;

    public IdGenerator(long dataCenterId, long machineId) {
        // 判断传入的参数是否合法
        if(dataCenterId > DATA_CENTER_MAX || machineId > MACHINE_MAX){
            throw new IllegalArgumentException("你传入的数据中心编号或机器号不合法.");
        }
        this.dataCenterId = dataCenterId;
        this.machineId = machineId;
    }

    public long getId(){
        long currentTime = System.currentTimeMillis();
        long timeStamp = currentTime - START_STAMP;


        // 判断时钟回拨
        if(timeStamp < lastTimeStamp){
            throw new RuntimeException("您的服务器进行了时钟回调.");
        }

        if (timeStamp == lastTimeStamp){
            sequenceId.increment();
            //同一时间获得的数字数量大于 序列号最大值 就等待下一时刻
            if(sequenceId.sum() >= SEQUENCE_MAX){
                timeStamp = getNextTimeStamp();
                sequenceId.reset();
            }
        } else {
            sequenceId.reset();
        }

        lastTimeStamp = timeStamp;
        /**
         * 同一时刻 每 获得一个数 序列号就加一
         */
        long sequence = sequenceId.sum();
        return timeStamp << TIMESTAMP_LEFT_OFFSET | dataCenterId << DATA_CENTER_LEFT_OFFSET
                | machineId << MACHINE_LEFT_OFFSET | sequence ;
    }


    private long getNextTimeStamp() {
        // 获取当前的时间戳
        long current = System.currentTimeMillis() - START_STAMP;
        // 如果一样就一直循环,直到下一个时间戳
        while (current == lastTimeStamp){
            current = System.currentTimeMillis() - START_STAMP;
        }
        return current;
    }
}

遗留问题:解决时钟回拨 后续处理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值