1 public class IdWorker 2 { 3 //基准时间 4 public const long Twepoch = 1288834974657L; 5 6 //机器标识位数 7 private const int WorkerIdBits = 6; 8 9 //数据标志位数 10 private const int DatacenterIdBits = 6; 11 12 //序列号识位数 13 private const int SequenceBits = 10; 14 15 //机器ID最大值 16 private const long MaxWorkerId = -1L ^ (-1L << WorkerIdBits); 17 18 //数据标志ID最大值 19 private const long MaxDatacenterId = -1L ^ (-1L << DatacenterIdBits); 20 21 //序列号ID最大值 22 private const long SequenceMask = -1L ^ (-1L << SequenceBits); 23 24 //机器ID偏左移10位 25 private const int WorkerIdShift = SequenceBits; 26 27 //数据ID偏左移15位 28 private const int DatacenterIdShift = SequenceBits + WorkerIdBits; 29 30 //时间毫秒左移20位 31 public const int TimestampLeftShift = SequenceBits + WorkerIdBits + DatacenterIdBits; 32 33 private static readonly DateTime Jan1St1970 = new DateTime 34 (1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); 35 36 private readonly object _lock = new object(); 37 private long _lastTimestamp = -1L; 38 39 public IdWorker(long workerId, long datacenterId, long sequence = 0L) 40 { 41 // 如果超出范围就抛出异常 42 if (workerId > MaxWorkerId || workerId < 0) 43 throw new ArgumentException(string.Format("worker Id 必须大于0,且不能大于MaxWorkerId: {0}", MaxWorkerId)); 44 45 if (datacenterId > MaxDatacenterId || datacenterId < 0) 46 throw new ArgumentException(string.Format("datacenterId Id 必须大于0,且不能大于MaxWorkerId: {0}", 47 MaxDatacenterId)); 48 49 //先检验再赋值 50 WorkerId = workerId; 51 DatacenterId = datacenterId; 52 Sequence = sequence; 53 } 54 55 public long WorkerId { get; protected set; } 56 public long DatacenterId { get; protected set; } 57 58 public long Sequence { get; internal set; } 59 60 public virtual long NextId(long dataNode=0) 61 { 62 lock (_lock) 63 { 64 if (dataNode > MaxDatacenterId || dataNode < 0) 65 throw new ArgumentException($"dataNode 必须大于0,且不能大于MaxWorkerId: {MaxDatacenterId}"); 66 if (dataNode == 0) 67 dataNode = DatacenterId; 68 var timestamp = TimeGen(); 69 if (timestamp < _lastTimestamp) 70 throw new Exception($"时间戳必须大于上一次生成ID的时间戳. 拒绝为{_lastTimestamp - timestamp}毫秒生成id"); 71 72 //如果上次生成时间和当前时间相同,在同一毫秒内 73 if (_lastTimestamp == timestamp) 74 { 75 //sequence自增,和sequenceMask相与一下,去掉高位 76 Sequence = (Sequence + 1) & SequenceMask; 77 //判断是否溢出,也就是每毫秒内超过1024,当为1024时,与sequenceMask相与,sequence就等于0 78 if (Sequence == 0) 79 timestamp = TilNextMillis(_lastTimestamp); 80 } 81 else 82 { 83 //如果和上次生成时间不同,重置sequence,就是下一毫秒开始,sequence计数重新从0开始累加, 84 //为了保证尾数随机性更大一些,最后一位可以设置一个随机数 85 Sequence = 0; //new Random().Next(10); 86 } 87 88 _lastTimestamp = timestamp; 89 return ((timestamp - Twepoch) << TimestampLeftShift) | (dataNode << DatacenterIdShift) | 90 (WorkerId << WorkerIdShift) | Sequence; 91 } 92 } 93 94 /// <summary> 95 /// 防止产生的时间比之前的时间还要小(由于NTP回拨等问题),保持增量的趋势. 96 /// </summary> 97 /// <param name="lastTimestamp"></param> 98 /// <returns></returns> 99 protected virtual long TilNextMillis(long lastTimestamp) 100 { 101 var timestamp = TimeGen(); 102 while (timestamp <= lastTimestamp) 103 timestamp = TimeGen(); 104 return timestamp; 105 } 106 107 /// <summary> 108 /// 获取当前的时间戳 109 /// </summary> 110 /// <returns></returns> 111 protected virtual long TimeGen() 112 { 113 return (long) (DateTime.UtcNow - Jan1St1970).TotalMilliseconds; 114 } 115 }
1 public void GetId() 2 { 3 new IdWorker(1, 1).NextId(); 4 }