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 版算法:spring
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 }
留個腳印,備用!less