demo系列-分布式ID-雪花算法

demo系列-分布式ID-雪花算法

说明

第1位:不使用
第[2,42]:毫秒级时间。可使用69年
第[43,47]:datacenterId
第[48,52]:workerId
[43,52]十位最多部署1024个节点
第[53,64]:毫秒内的计数/序列号

Long的值

0, 时间截=当前-开始, 数据中心Id+机器Id,12位序列号

代码

public class Snowflake {
    /*
    第1位:不使用
    第[2,42]:毫秒级时间。可使用69年
    第[43,47]:dataCenterId
    第[48,52]:workerId
        [43,52]十位最多部署1024个节点
    第[53,64]:毫秒内的计数/序列号

    1. 开始时间戳
    2. 所占位数:时间截、数据中心、机器、序列号
    3. 最大值:时间截、数据中心、机器、序列号
    4. 移位:
    5. 存储位:时间截,机器Id,数据中心Id,序列号Id
     */
    // 1. 开始时间戳
    private final long epoch = System.currentTimeMillis();
    // 2. 所占位数
    private final long[] bits = {41L, 5L, 5L, 12L};
    // 3. 最大值
    private final long[] max = {-1L ^ (-1L << bits[0]), -1L ^ (-1L << bits[1]), -1L ^ (-1L << bits[2]), -1L ^ (-1L << bits[3])};
    // 4. 移位
    private final long[] move = {bits[1] + bits[2] + bits[3], bits[2] + bits[3], bits[3]};
    // 5. 对应域的当前值
    private long timestamp = -1L;
    private long dataCenterId;
    private long workerId;
    private long sequence = 0L;

    /**
     * 0表示时间截,1表示数据中心,2表示机器Id,3表示序列号。使用枚举量比较好,此处省事
     * @param index
     * @param cur
     * @return
     */
    private boolean checkRange(int index, long cur) {
        if (cur < 0 || cur > max[index]) {
            return true;
        }
        return false;
    }

    public Snowflake(long dataCenterId, long workerId) {
        if (checkRange(1, dataCenterId)) {
            String info = String.format("数据中心Id的范围应为:[0, {}]",  max[1]);
            throw new IllegalArgumentException(info + ";当前为:" + dataCenterId);
        }
        if (checkRange(2, workerId)) {
            String info = String.format("机器Id的范围应为:[0, {}]",  max[2]);
            throw new IllegalArgumentException(info + ";当前为:" + workerId);
        }
        this.dataCenterId = dataCenterId;
        this.workerId = workerId;
    }

    public synchronized long nextId() {
        long timestamp = timeGen();
        if (timestamp < this.timestamp) {
            // 当前时间 < 上一次时间。系统时钟回退,应抛出异常
            String info = String.format("系统时钟回退,拒绝生成时间截:{},上一次时间截:{}", timestamp - epoch, this.timestamp - epoch);
            throw new RuntimeException(info);
        } else if (timestamp == this.timestamp) {
            // 同一毫秒内生成,则序列号升序
            sequence = (sequence + 1) % max[3];
            if (sequence == 0) {
                System.out.println("max:" + max[3]);
                // 序列溢出,比如同一毫秒内生成id过多,超出序列号最大值12的4096-1=4095
                timestamp = nextMills(this.timestamp);
            }
        } else {
            sequence = 0L;
        }
        // 更新this.timestamp
        this.timestamp = timestamp;
        return ((timestamp - epoch) << move[0] | dataCenterId << move[1] | workerId << move[2] | sequence);
    }

    protected long timeGen() {
        return System.currentTimeMillis();
    }
    protected long nextMills(long last) {
        long timestamp = timeGen();
        while (timestamp <= last) {
            timestamp = timeGen();
        }
        return timestamp;
    }

    public static void main(String[] args) {
        Snowflake snowflake = new Snowflake(0, 0);
        for (int i = 0; i < 10000; ++i) {
            long id = snowflake.nextId();
            System.out.println(Long.toBinaryString(id));
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值