zoukankan      html  css  js  c++  java
  • 根据twitter的snowflake算法生成唯一ID

    C#版本

    复制代码
    /// <summary>
        /// 根据twitter的snowflake算法生成唯一ID
        /// snowflake算法 64 位
        /// 0---0000000000 0000000000 0000000000 0000000000 0 --- 00000 ---00000 ---000000000000
        /// 第一位为未使用(实际上也可作为long的符号位),接下来的41位为毫秒级时间,然后5位datacenter标识位,5位机器ID(并不算标识符,实际是为线程标识),然后12位该毫秒内的当前毫秒内的计数,加起来刚好64位,为一个Long型。
        /// 其中datacenter标识位起始是机器位,机器ID其实是线程标识,可以同一一个10位来表示不同机器
        /// </summary>
        public class IdWorker
        {
            //机器ID
            private static long workerId = 1;
            private static long twepoch = 687888001020L; //唯一时间,这是一个避免重复的随机量,自行设定不要大于当前时间戳
            private static long sequence = 0L;
            private static int workerIdBits = 4; //机器码字节数。4个字节用来保存机器码
            public static long maxWorkerId = -1L ^ -1L << workerIdBits; //最大机器ID
            private static int sequenceBits = 10; //计数器字节数,10个字节用来保存计数码
            private static int workerIdShift = sequenceBits; //机器码数据左移位数,就是后面计数器占用的位数
            private static int timestampLeftShift = sequenceBits + workerIdBits; //时间戳左移动位数就是机器码和计数器总字节数
            public static long sequenceMask = -1L ^ -1L << sequenceBits; //一微秒内可以产生计数,如果达到该值则等到下一微妙在进行生成
            private long lastTimestamp = -1L;
    
            public long nextId()
            {
                lock (this)
                {
                    long timestamp = timeGen();
                    if (this.lastTimestamp == timestamp)
                    { //同一微妙中生成ID
                        IdWorker.sequence = (IdWorker.sequence + 1) & IdWorker.sequenceMask; //用&运算计算该微秒内产生的计数是否已经到达上限
                        if (IdWorker.sequence == 0)
                        {
                            //一微妙内产生的ID计数已达上限,等待下一微妙
                            timestamp = tillNextMillis(this.lastTimestamp);
                        }
                    }
                    else
                    { //不同微秒生成ID
                        IdWorker.sequence = 0; //计数清0
                    }
                    if (timestamp < lastTimestamp)
                    { //如果当前时间戳比上一次生成ID时时间戳还小,抛出异常,因为不能保证现在生成的ID之前没有生成过
                        throw new Exception(string.Format("Clock moved backwards.  Refusing to generate id for {0} milliseconds",
                            this.lastTimestamp - timestamp));
                    }
                    this.lastTimestamp = timestamp; //把当前时间戳保存为最后生成ID的时间戳
                    long nextId = (timestamp - twepoch << timestampLeftShift) | IdWorker.workerId << IdWorker.workerIdShift | IdWorker.sequence;
                    return nextId;
                }
            }
    
            /// <summary>
            /// 获取下一微秒时间戳
            /// </summary>
            /// <param name="lastTimestamp"></param>
            /// <returns></returns>
            private long tillNextMillis(long lastTimestamp)
            {
                long timestamp = timeGen();
                while (timestamp <= lastTimestamp)
                {
                    timestamp = timeGen();
                }
                return timestamp;
            }
    
            /// <summary>
            /// 生成当前时间戳
            /// </summary>
            /// <returns></returns>
            private long timeGen()
            {
                return (long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds;
            }
        }
    复制代码

    JAVA版本

    复制代码
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;
    
    public class IdWorker {
    
        protected static final Logger LOG = LoggerFactory.getLogger(IdWorker.class);
    
        private long workerId;
        private long datacenterId;
        private long sequence = 0L;
    
        private long twepoch = 1288834974657L;
    
        private long workerIdBits = 5L;
        private long datacenterIdBits = 5L;
        private long maxWorkerId = -1L ^ (-1L << workerIdBits);
        private long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
        private long sequenceBits = 12L;
    
        private long workerIdShift = sequenceBits;
        private long datacenterIdShift = sequenceBits + workerIdBits;
        private long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
        private long sequenceMask = -1L ^ (-1L << sequenceBits);
    
        private long lastTimestamp = -1L;
    
        public IdWorker(long workerId, long datacenterId) {
            // sanity check for workerId
            if (workerId > maxWorkerId || workerId < 0) {
                throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
            }
            if (datacenterId > maxDatacenterId || datacenterId < 0) {
                throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
            }
            this.workerId = workerId;
            this.datacenterId = datacenterId;
            LOG.info(String.format("worker starting. timestamp left shift %d, datacenter id bits %d, worker id bits %d, sequence bits %d, workerid %d", timestampLeftShift, datacenterIdBits, workerIdBits, sequenceBits, workerId));
        }
    
        public synchronized long nextId() {
            long timestamp = timeGen();
    
            if (timestamp < lastTimestamp) {
                LOG.error(String.format("clock is moving backwards.  Rejecting requests until %d.", lastTimestamp));
                throw new RuntimeException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
            }
    
            if (lastTimestamp == timestamp) {
                sequence = (sequence + 1) & sequenceMask;
                if (sequence == 0) {
                    timestamp = tilNextMillis(lastTimestamp);
                }
            } else {
                sequence = 0L;
            }
    
            lastTimestamp = timestamp;
    
            return ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | sequence;
        }
    
        protected long tilNextMillis(long lastTimestamp) {
            long timestamp = timeGen();
            while (timestamp <= lastTimestamp) {
                timestamp = timeGen();
            }
            return timestamp;
        }
    
        protected long timeGen() {
            return System.currentTimeMillis();
        }
    
    
    }
    复制代码
     
     
  • 相关阅读:
    UVA
    UVA
    UVA
    UVA
    POJ
    Yahoo Programming Contest 2019 自闭记
    Codeforces Global Round 1 自闭记
    CodeCraft-19 and Codeforces Round #537 Div. 2
    BZOJ4912 SDOI2017天才黑客(最短路+虚树)
    BZOJ2877 NOI2012魔幻棋盘(二维线段树)
  • 原文地址:https://www.cnblogs.com/soundcode/p/7199356.html
Copyright © 2011-2022 走看看