• 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 }

    留个脚印,备用!

  • 相关阅读:
    896. Monotonic Array单调数组
    865. Smallest Subtree with all the Deepest Nodes 有最深节点的最小子树
    489. Robot Room Cleaner扫地机器人
    JavaFX
    《Python CookBook2》 第一章 文本
    《Python CookBook2》 第一章 文本
    《Python CookBook2》 第一章 文本
    《Python CookBook2》 第一章 文本
    《Python CookBook2》 第一章 文本
    《Python CookBook2》 第一章 文本
  • 原文地址:https://www.cnblogs.com/yuwentao/p/8004102.html
Copyright © 2020-2023  润新知