SnowFlake.cs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. using Masuit.Tools.DateTimeExt;
  2. using Masuit.Tools.Strings;
  3. using System;
  4. namespace Masuit.Tools.Systems
  5. {
  6. /// <summary>
  7. /// 动态生产有规律的分布式ID
  8. /// </summary>
  9. public class SnowFlake
  10. {
  11. #region 私有字段
  12. private static long _machineId; //机器码
  13. private static long _dataId; //数据ID
  14. private static long _sequence; //计数从零开始
  15. private static long _lastTimestamp = -1L; //最后时间戳
  16. private const long Twepoch = 687888001020L; //唯一时间随机量
  17. private const long MachineIdBits = 5L; //机器码字节数
  18. private const long DataBits = 5L; //数据字节数
  19. private const long MaxMachineId = -1L ^ -1L << (int)MachineIdBits; //最大机器码
  20. private const long MaxDataBitId = -1L ^ (-1L << (int)DataBits); //最大数据字节数
  21. private const long SequenceBits = 12L; //计数器字节数,12个字节用来保存计数码
  22. private const long MachineIdShift = SequenceBits; //机器码数据左移位数,就是后面计数器占用的位数
  23. private const long DatacenterIdShift = SequenceBits + MachineIdBits;
  24. private const long TimestampLeftShift = DatacenterIdShift + DataBits; //时间戳左移动位数就是机器码+计数器总字节数+数据字节数
  25. private const long SequenceMask = -1L ^ -1L << (int)SequenceBits; //一毫秒内可以产生计数,如果达到该值则等到下一毫秒在进行生成
  26. private static readonly object SyncRoot = new object(); //加锁对象
  27. private static NumberFormater _numberFormater = new NumberFormater(36);
  28. private static SnowFlake _snowFlake;
  29. #endregion
  30. /// <summary>
  31. /// 获取一个新的id
  32. /// </summary>
  33. public static string NewId => GetInstance().GetUniqueId();
  34. /// <summary>
  35. /// 创建一个实例
  36. /// </summary>
  37. /// <returns></returns>
  38. public static SnowFlake GetInstance()
  39. {
  40. return _snowFlake ??= new SnowFlake();
  41. }
  42. /// <summary>
  43. /// 默认构造函数
  44. /// </summary>
  45. public SnowFlake()
  46. {
  47. Snowflakes(0, -1);
  48. }
  49. /// <summary>
  50. /// 构造函数
  51. /// </summary>
  52. /// <param name="machineId">机器码</param>
  53. public SnowFlake(long machineId)
  54. {
  55. Snowflakes(machineId, -1);
  56. }
  57. /// <summary>
  58. /// 构造函数
  59. /// </summary>
  60. /// <param name="machineId">机器码</param>
  61. /// <param name="datacenterId">数据中心id</param>
  62. public SnowFlake(long machineId, long datacenterId)
  63. {
  64. Snowflakes(machineId, datacenterId);
  65. }
  66. private void Snowflakes(long machineId, long datacenterId)
  67. {
  68. if (machineId >= 0)
  69. {
  70. if (machineId > MaxMachineId)
  71. {
  72. throw new Exception("机器码ID非法");
  73. }
  74. _machineId = machineId;
  75. }
  76. if (datacenterId >= 0)
  77. {
  78. if (datacenterId > MaxDataBitId)
  79. {
  80. throw new Exception("数据中心ID非法");
  81. }
  82. _dataId = datacenterId;
  83. }
  84. }
  85. /// <summary>
  86. /// 设置数制格式化器
  87. /// </summary>
  88. /// <param name="nf"></param>
  89. public static void SetNumberFormater(NumberFormater nf)
  90. {
  91. _numberFormater = nf;
  92. }
  93. /// <summary>
  94. /// 获取长整形的ID
  95. /// </summary>
  96. /// <returns></returns>
  97. public long GetLongId()
  98. {
  99. lock (SyncRoot)
  100. {
  101. var timestamp = DateTime.UtcNow.GetTotalMilliseconds();
  102. if (_lastTimestamp == timestamp)
  103. {
  104. //同一毫秒中生成ID
  105. _sequence = (_sequence + 1) & SequenceMask; //用&运算计算该毫秒内产生的计数是否已经到达上限
  106. if (_sequence == 0)
  107. {
  108. //一毫秒内产生的ID计数已达上限,等待下一毫秒
  109. timestamp = DateTime.UtcNow.GetTotalMilliseconds();
  110. }
  111. }
  112. else
  113. {
  114. //不同毫秒生成ID
  115. _sequence = 0L;
  116. }
  117. _lastTimestamp = timestamp; //把当前时间戳保存为最后生成ID的时间戳
  118. long id = ((timestamp - Twepoch) << (int)TimestampLeftShift) | (_dataId << (int)DatacenterIdShift) | (_machineId << (int)MachineIdShift) | _sequence;
  119. return id;
  120. }
  121. }
  122. /// <summary>
  123. /// 获取一个字符串表示形式的id
  124. /// </summary>
  125. /// <returns></returns>
  126. public string GetUniqueId()
  127. {
  128. return _numberFormater.ToString(GetLongId());
  129. }
  130. /// <summary>
  131. /// 获取一个字符串表示形式的id
  132. /// </summary>
  133. /// <param name="maxLength">最大长度,至少6位</param>
  134. /// <returns></returns>
  135. public string GetUniqueShortId(int maxLength = 8)
  136. {
  137. if (maxLength < 6)
  138. {
  139. throw new ArgumentException("最大长度至少需要6位");
  140. }
  141. string id = GetUniqueId();
  142. int index = id.Length - maxLength;
  143. if (index < 0)
  144. {
  145. index = 0;
  146. }
  147. return id.Substring(index);
  148. }
  149. }
  150. }