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 }
留个脚印,备用!