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 }

 

留个脚印,备用!

posted @ 2017-12-08 10:05  DotNet码农  阅读(769)  评论(0编辑  收藏
/*粒子线条,鼠标移动会以鼠标为中心吸附的特效*/