1. 程式人生 > >C# 根據twitter的snowflake算法生成唯一ID

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

%d req sync protected ons java 沒有 total gre

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 }

留個腳印,備用!

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