• C# 根据twitter的snowflake算法生成唯一ID


    C# 版算法:

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 
     7 namespace Demo
     8 {
     9 
    10         /// <summary>
    11         /// 根据twitter的snowflake算法生成唯一ID
    12         /// snowflake算法 64 位
    13         /// 0---0000000000 0000000000 0000000000 0000000000 0 --- 00000 ---00000 ---000000000000
    14         /// 第一位为未使用(实际上也可作为long的符号位),接下来的41位为毫秒级时间,然后5位datacenter标识位,5位机器ID(并不算标识符,实际是为线程标识),然后12位该毫秒内的当前毫秒内的计数,加起来刚好64位,为一个Long型。
    15         /// 其中datacenter标识位起始是机器位,机器ID其实是线程标识,可以同一一个10位来表示不同机器
    16         /// </summary>
    17         public class IdWorker
    18         {
    19             //机器ID
    20             private static long workerId = 1;
    21             private static long twepoch = 687888001020L; //唯一时间,这是一个避免重复的随机量,自行设定不要大于当前时间戳
    22             private static long sequence = 0L;
    23             private static int workerIdBits = 4; //机器码字节数。4个字节用来保存机器码
    24             public static long maxWorkerId = -1L ^ -1L << workerIdBits; //最大机器ID
    25             private static int sequenceBits = 10; //计数器字节数,10个字节用来保存计数码
    26             private static int workerIdShift = sequenceBits; //机器码数据左移位数,就是后面计数器占用的位数
    27             private static int timestampLeftShift = sequenceBits + workerIdBits; //时间戳左移动位数就是机器码和计数器总字节数
    28             public static long sequenceMask = -1L ^ -1L << sequenceBits; //一微秒内可以产生计数,如果达到该值则等到下一微妙在进行生成
    29             private long lastTimestamp = -1L;
    30 
    31             public long nextId()
    32             {
    33                 lock (this)
    34                 {
    35                     long timestamp = timeGen();
    36                     if (this.lastTimestamp == timestamp)
    37                     { //同一微妙中生成ID
    38                         IdWorker.sequence = (IdWorker.sequence + 1) & IdWorker.sequenceMask; //用&运算计算该微秒内产生的计数是否已经到达上限
    39                         if (IdWorker.sequence == 0)
    40                         {
    41                             //一微妙内产生的ID计数已达上限,等待下一微妙
    42                             timestamp = tillNextMillis(this.lastTimestamp);
    43                         }
    44                     }
    45                     else
    46                     { //不同微秒生成ID
    47                         IdWorker.sequence = 0; //计数清0
    48                     }
    49                     if (timestamp < lastTimestamp)
    50                     { //如果当前时间戳比上一次生成ID时时间戳还小,抛出异常,因为不能保证现在生成的ID之前没有生成过
    51                         throw new Exception(string.Format("Clock moved backwards.  Refusing to generate id for {0} milliseconds",
    52                             this.lastTimestamp - timestamp));
    53                     }
    54                     this.lastTimestamp = timestamp; //把当前时间戳保存为最后生成ID的时间戳
    55                     long nextId = (timestamp - twepoch << timestampLeftShift) | IdWorker.workerId << IdWorker.workerIdShift | IdWorker.sequence;
    56                     return nextId;
    57                 }
    58             }
    59 
    60             /// <summary>
    61             /// 获取下一微秒时间戳
    62             /// </summary>
    63             /// <param name="lastTimestamp"></param>
    64             /// <returns></returns>
    65             private long tillNextMillis(long lastTimestamp)
    66             {
    67                 long timestamp = timeGen();
    68                 while (timestamp <= lastTimestamp)
    69                 {
    70                     timestamp = timeGen();
    71                 }
    72                 return timestamp;
    73             }
    74 
    75             /// <summary>
    76             /// 生成当前时间戳
    77             /// </summary>
    78             /// <returns></returns>
    79             private long timeGen()
    80             {
    81                 return (long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds;
    82             }
    83         }
    84     }

    Java 版算法:

     1 import org.slf4j.Logger;
     2 import org.slf4j.LoggerFactory;
     3 import org.springframework.stereotype.Component;
     4 
     5 public class IdWorker {
     6 
     7     protected static final Logger LOG = LoggerFactory.getLogger(IdWorker.class);
     8 
     9     private long workerId;
    10     private long datacenterId;
    11     private long sequence = 0L;
    12 
    13     private long twepoch = 1288834974657L;
    14 
    15     private long workerIdBits = 5L;
    16     private long datacenterIdBits = 5L;
    17     private long maxWorkerId = -1L ^ (-1L << workerIdBits);
    18     private long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
    19     private long sequenceBits = 12L;
    20 
    21     private long workerIdShift = sequenceBits;
    22     private long datacenterIdShift = sequenceBits + workerIdBits;
    23     private long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
    24     private long sequenceMask = -1L ^ (-1L << sequenceBits);
    25 
    26     private long lastTimestamp = -1L;
    27 
    28     public IdWorker(long workerId, long datacenterId) {
    29         // sanity check for workerId
    30         if (workerId > maxWorkerId || workerId < 0) {
    31             throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
    32         }
    33         if (datacenterId > maxDatacenterId || datacenterId < 0) {
    34             throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
    35         }
    36         this.workerId = workerId;
    37         this.datacenterId = datacenterId;
    38         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));
    39     }
    40 
    41     public synchronized long nextId() {
    42         long timestamp = timeGen();
    43 
    44         if (timestamp < lastTimestamp) {
    45             LOG.error(String.format("clock is moving backwards.  Rejecting requests until %d.", lastTimestamp));
    46             throw new RuntimeException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
    47         }
    48 
    49         if (lastTimestamp == timestamp) {
    50             sequence = (sequence + 1) & sequenceMask;
    51             if (sequence == 0) {
    52                 timestamp = tilNextMillis(lastTimestamp);
    53             }
    54         } else {
    55             sequence = 0L;
    56         }
    57 
    58         lastTimestamp = timestamp;
    59 
    60         return ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | sequence;
    61     }
    62 
    63     protected long tilNextMillis(long lastTimestamp) {
    64         long timestamp = timeGen();
    65         while (timestamp <= lastTimestamp) {
    66             timestamp = timeGen();
    67         }
    68         return timestamp;
    69     }
    70 
    71     protected long timeGen() {
    72         return System.currentTimeMillis();
    73     }
    74 
    75 
    76 }

    留个脚印,备用!

  • 相关阅读:
    java中用spring实现数组类型输出
    #科委外文文献发现系统——导出word模板1.0
    #科委外文文献发现系统——项目管理
    终审项目展示
    M2事后会议报告
    【Beta版本发布】爬虫队长装备全面更新!
    Beta版本测试报告
    Beta阶段爬取数目预估
    团队作业Week14——源代码管理
    Daily Scrum NO.10
  • 原文地址:https://www.cnblogs.com/yuwentao/p/8004102.html
Copyright © 2020-2023  润新知