SnowFlake.cs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  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 _datacenterId; //数据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 DatacenterIdBits = 5L; //数据字节数
  19. private const long MaxMachineId = -1L ^ -1L << (int)MachineIdBits; //最大机器码
  20. private const long MaxDatacenterId = -1L ^ (-1L << (int)DatacenterIdBits); //最大数据ID
  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 + DatacenterIdBits; //时间戳左移动位数就是机器码+计数器总字节数+数据字节数
  25. private const long SequenceMask = -1L ^ -1L << (int)SequenceBits; //一毫秒内可以产生计数,如果达到该值则等到下一毫秒在进行生成
  26. private static readonly object SyncRoot = new object(); //加锁对象
  27. private static readonly NumberFormater NumberFormater = new NumberFormater(36);
  28. private static SnowFlake _snowFlake;
  29. #endregion
  30. /// <summary>
  31. /// 创建一个实例
  32. /// </summary>
  33. /// <returns></returns>
  34. public static SnowFlake GetInstance()
  35. {
  36. return _snowFlake ?? (_snowFlake = new SnowFlake());
  37. }
  38. /// <summary>
  39. /// 默认构造函数
  40. /// </summary>
  41. public SnowFlake()
  42. {
  43. Snowflakes(0, -1);
  44. }
  45. /// <summary>
  46. /// 构造函数
  47. /// </summary>
  48. /// <param name="machineId">机器码</param>
  49. public SnowFlake(long machineId)
  50. {
  51. Snowflakes(machineId, -1);
  52. }
  53. /// <summary>
  54. /// 构造函数
  55. /// </summary>
  56. /// <param name="machineId">机器码</param>
  57. /// <param name="datacenterId">数据中心id</param>
  58. public SnowFlake(long machineId, long datacenterId)
  59. {
  60. Snowflakes(machineId, datacenterId);
  61. }
  62. private void Snowflakes(long machineId, long datacenterId)
  63. {
  64. if (machineId >= 0)
  65. {
  66. if (machineId > MaxMachineId)
  67. {
  68. throw new Exception("机器码ID非法");
  69. }
  70. _machineId = machineId;
  71. }
  72. if (datacenterId >= 0)
  73. {
  74. if (datacenterId > MaxDatacenterId)
  75. {
  76. throw new Exception("数据中心ID非法");
  77. }
  78. _datacenterId = datacenterId;
  79. }
  80. }
  81. /// <summary>
  82. /// 获取长整形的ID
  83. /// </summary>
  84. /// <returns></returns>
  85. public long GetLongId()
  86. {
  87. lock (SyncRoot)
  88. {
  89. var timestamp = (long)DateTime.UtcNow.GetTotalMilliseconds();
  90. if (_lastTimestamp == timestamp)
  91. {
  92. //同一毫秒中生成ID
  93. _sequence = (_sequence + 1) & SequenceMask; //用&运算计算该毫秒内产生的计数是否已经到达上限
  94. if (_sequence == 0)
  95. {
  96. //一毫秒内产生的ID计数已达上限,等待下一毫秒
  97. timestamp = (long)DateTime.UtcNow.GetTotalMilliseconds();
  98. }
  99. }
  100. else
  101. {
  102. //不同毫秒生成ID
  103. _sequence = 0L;
  104. }
  105. _lastTimestamp = timestamp; //把当前时间戳保存为最后生成ID的时间戳
  106. long id = ((timestamp - Twepoch) << (int)TimestampLeftShift) | (_datacenterId << (int)DatacenterIdShift) | (_machineId << (int)MachineIdShift) | _sequence;
  107. return id;
  108. }
  109. }
  110. /// <summary>
  111. /// 获取一个字符串表示形式的id
  112. /// </summary>
  113. /// <returns></returns>
  114. public string GetUniqueId()
  115. {
  116. return NumberFormater.ToString(GetLongId());
  117. }
  118. /// <summary>
  119. /// 获取一个字符串表示形式的id
  120. /// </summary>
  121. /// <param name="maxLength">最大长度,至少6位</param>
  122. /// <returns></returns>
  123. public string GetUniqueShortId(int maxLength = 8)
  124. {
  125. if (maxLength < 6)
  126. {
  127. throw new ArgumentException("最大长度至少需要6位");
  128. }
  129. string id = GetUniqueId();
  130. int index = id.Length - maxLength;
  131. if (index < 0)
  132. {
  133. index = 0;
  134. }
  135. return id.Substring(index);
  136. }
  137. }
  138. }