IdWorker.cs 4.9 KB

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