SnonFlke雪花算法生成ID

SnowFlake算法生成id的结果是一个64bit大小的整数,它的结构如下图:
在这里插入图片描述
图片描述

1位,不用。二进制中最高位为1的都是负数,但是我们生成的id一般都使用整数,所以这个最高位固定是0
41位,用来记录时间戳(毫秒)。

41位可以表示 2 41 − 1 2^{41}-1 2411个数字,
如果只用来表示正整数(计算机中正数包含0),可以表示的数值范围是:0 至 2 41 − 1 2^{41}-1 2411,减1是因为可表示的数值范围是从0开始算的,而不是1。
也就是说41位可以表示 2 41 − 1 2^{41}-1 2411个毫秒的值,转化成单位年则是 ( 2 41 − 1 ) / ( 1000 ∗ 60 ∗ 60 ∗ 24 ∗ 365 ) = 69 (2^{41}-1) / (1000 * 60 * 60 * 24 * 365) = 69 (2411)/(1000606024365)=69
10位,用来记录工作机器id。

可以部署在 2 10 = 1024 2^{10} = 1024 210=1024个节点,包括5位datacenterId和5位workerId
5位(bit)可以表示的最大正整数是 2 5 − 1 = 31 2^{5}-1 = 31 251=31,即可以用0、1、2、3、…31这32个数字,来表示不同的datecenterId或workerId
12位,序列号,用来记录同毫秒内产生的不同id。

12位(bit)可以表示的最大正整数是 2 12 − 1 = 4095 2^{12}-1 = 4095 2121=4095,即可以用0、1、2、3、…4094这4095个数字,来表示同一机器同一时间截(毫秒)内产生的4095个ID序号
由于在Java中64bit的整数是long类型,所以在Java中SnowFlake算法生成的id就是long来存储的。

SnowFlake可以保证:

所有生成的id按时间趋势递增
整个分布式系统内不会产生重复id(因为有datacenterId和workerId来做区分)

 private static long datacenterId=0L;//数据中心
        private static long machineId;//机器id
        private static long sequence = 0L;//计数0开始
        private static long lastTimestamp = -1L;//最后时间戳

        private static long twepoch = 687888001020L;//唯一时间随机量

        private static long machineIdBits = 5L;//机器码字节数
        private static long datacenterIdBits = 5L;//数据字节
        private static long maxMachineId=-1L ^ -1L << (int)machineIdBits;//机器最大id
        private static long maxDatacenterId = -1L ^ (-1L << (int)datacenterIdBits);//最大数据ID


        private static long sequenceBits = 12L;//计数器字节数,12个字节用来保存计数码
        private static long machineIdShift = sequenceBits;//机器码数据左位移,就是后面计数器占用的位数
        private static long datacenterIdShift = sequenceBits + machineIdBits;
        private static long timestampLeftShift = sequenceBits + machineIdBits+datacenterIdBits;//时间戳左移动位数就是机器码+计数器总字节数+数据字节数
        public static long sequenceMask = -1L ^ -1L << (int)sequenceBits;//一微秒可以产生计数,如果达到该值则等到下一微秒在进行生成

        private static object syncRoot = new object();//加锁对象
        static Snowflake snowflake;

        public static Snowflake Instance()
        {
            if (snowflake==null)
                snowflake = new Snowflake(); 
            return snowflake;
        }

        public Snowflake()
        {
            Snowflakes(0L, -1);
        }

        public Snowflake(long machineId)
        {
            Snowflakes(machineId, -1);
        }

        public Snowflake(long manchineId, long datacenterId)
        {
            Snowflakes(manchineId, datacenterId);
        }

        private void Snowflakes(long machineld, long datacenterid)
        {
            if (machineId>=0)
            {
                if (machineId>maxMachineId)
                {
                    throw new Exception("机器码DI非法");
                }
                Snowflake.maxMachineId = machineId;
            }
            if (datacenterid>=0)
            {
                if (datacenterid>maxDatacenterId)
                {
                    throw new Exception("数据中心ID非法");
                }
                Snowflake.datacenterId = datacenterId;
            }

        }

        /// <summary>
        /// 生成当前事件戳
        /// </summary>
        /// <returns>毫秒returns>
        private static long GetTimestamp()
        {
            //从2000年开始
            return (long)(DateTime.UtcNow - new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds;
        }
        /// <summary>
        /// 获取下一微妙时间戳
        /// </summary>
        /// <param name="lastTimestamp"></param>
        /// <returns></returns>
        private static long GetNextTimestamp(long lastTimestamp)
        {
            //调用获取时间
            long timestamp = GetTimestamp();
            //判断两个时间戳大小
            if (timestamp<=lastTimestamp)
            {
                timestamp = GetTimestamp();
            }
            return timestamp;
        }

        public static long GetId()
        {
            lock (syncRoot)
            {
                long timestamp = GetTimestamp();
                if (Snowflake.lastTimestamp==timestamp)
                {
                    //同一微妙中生成ID
                    sequence = (sequence + 1) & sequenceMask;
                    //利用&运算计算该微妙内产生的计数是否已经达到上限
                    if (sequence==0)
                    {
                        //一微秒内产生的ID计数已达上限,请等待下一微妙
                        timestamp = GetNextTimestamp(Snowflake.lastTimestamp);
                    }
                }
                else
                {
                    //不同微妙生成ID
                    sequence = 0L;
                }
                if (timestamp<lastTimestamp)
                {
                    throw new Exception("时间戳大小异常!");
                }
                Snowflake.lastTimestamp = timestamp;//把当前时间戳保存为最后生成ID的时间戳
                long Id = ((timestamp - twepoch)) << (int)timestampLeftShift
                    | (datacenterId << (int)datacenterIdShift)
                    | (machineId << (int)machineIdShift)
                    | sequence;
                return Id;

            }
        }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值