zoukankan      html  css  js  c++  java
  • 雪花算法(SnowFlake)

    组成结构图

    代码实现(基于上图)

    public class SnowFlakeGenerator {
    
        private long roomId; //机房id
    
        private long workerId; //机器id
    
        private long roomIdBit = 5l; //占用5个bit位
    
        private long workerIdBit = 5l;//占用5个bit位
    
        //声明roomId最大的正整数 32
        private long maxRoomId = -1l ^ (-1l << roomIdBit);
        private long maxWorkerId = -1l ^ (-1l << workerIdBit);
    
        private long sequenceBits = 12l; //12bit的递增序列
    
        private long sequence; //递增开始的序列
    
        public SnowFlakeGenerator(long roomId, long workerId, long sequence) {
            if (workerId > maxWorkerId || workerId < 0) {
                throw new IllegalArgumentException("worker Id错误");
            }
            if (roomId > maxRoomId || roomId < 0) {
                throw new IllegalArgumentException("roomId Id错误");
            }
            this.roomId = roomId;
            this.workerId = workerId;
            this.sequence = sequence;
        }
    
        private long sequenceMask = -1l ^ (-1l << sequenceBits);
        private long lastTimeStamp = -1l; //存储上一次生成的id的时间戳
    
        private long twepoch = 1596372483166L;//初始的时间值
    
        private long workerIdShift = sequenceBits;
    
        private long roomIdShift = sequenceBits + workerIdBit;
        private long timeStampShift = sequenceBits + workerIdBit + roomIdBit;
    
        public synchronized long nextVal() {
    
            long timestamp = System.currentTimeMillis();
            if (timestamp < lastTimeStamp) {
                throw new RuntimeException("时间戳异常");
            }
            if (lastTimeStamp == timestamp) {
                sequence = (sequence + 1) & sequenceMask;
                if (sequence == 0) {
                    timestamp = waitToNextMills(lastTimeStamp);
                }
            } else {
                //如果进入到了新的时间毫秒,sequence从0开始
                sequence = timestamp & 1;
            }
            lastTimeStamp = timestamp;
            return ((timestamp - twepoch) << timeStampShift | (roomId << roomIdShift) | (workerId << workerIdShift) | sequence);
        }
    
        public long waitToNextMills(long lastTimeStamp) {
            long timeStamp = System.currentTimeMillis();
            while (timeStamp <= lastTimeStamp) {
                timeStamp = System.currentTimeMillis();
            }
            return timeStamp;
        }
    
        public static void main(String[] args) throws InterruptedException {
            SnowFlakeGenerator snowFlakeGenerator = new SnowFlakeGenerator(1,1,1);
            for (int i = 0; i < 100; i++) {
                Thread.sleep(1);
                System.out.println(snowFlakeGenerator.nextVal());
            }
    
        }
    }
    

    这种方式的优缺点是:

    优点:

    • 毫秒数在高位,自增序列在低位,整个ID都是趋势递增的。
    • 不依赖数据库等第三方系统,以服务的方式部署,稳定性更高,生成ID的性能也是非常高的。
    • 可以根据自身业务特性分配bit位,非常灵活。

    缺点:

    • 强依赖机器时钟,如果机器上时钟回拨,会导致发号重复或者服务会处于不可用状态。
  • 相关阅读:
    poj1988
    sgu488
    Walking around Berhattan
    基于矩阵分解的简单推荐算法
    Funny Feature
    php面向对象
    PHPstorm快捷键
    创建UIImage的两种方法
    dismissViewControllerAnimated有延迟
    17个常用代码整理
  • 原文地址:https://www.cnblogs.com/snail-gao/p/14141863.html
Copyright © 2011-2022 走看看