Snowflake.cs 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. namespace Ant.Core.Utils
  7. {
  8. /// <summary>
  9. /// 雪花算法
  10. /// </summary>
  11. public class Snowflake
  12. {
  13. private static long machineId;//机器ID
  14. private static long datacenterId = 0L;//数据ID
  15. private static long sequence = 0L;//计数从零开始
  16. private static long twepoch = 687888001020L; //唯一时间随机量
  17. private static long machineIdBits = 5L; //机器码字节数
  18. private static long datacenterIdBits = 5L;//数据字节数
  19. public static long maxMachineId = -1L ^ -1L << (int)machineIdBits; //最大机器ID
  20. private static long maxDatacenterId = -1L ^ (-1L << (int)datacenterIdBits);//最大数据ID
  21. private static long sequenceBits = 12L; //计数器字节数,12个字节用来保存计数码
  22. private static long machineIdShift = sequenceBits; //机器码数据左移位数,就是后面计数器占用的位数
  23. private static long datacenterIdShift = sequenceBits + machineIdBits;
  24. private static long timestampLeftShift = sequenceBits + machineIdBits + datacenterIdBits; //时间戳左移动位数就是机器码+计数器总字节数+数据字节数
  25. public static long sequenceMask = -1L ^ -1L << (int)sequenceBits; //一微秒内可以产生计数,如果达到该值则等到下一微妙在进行生成
  26. private static long lastTimestamp = -1L;//最后时间戳
  27. private static object syncRoot = new object();//加锁对象
  28. static Snowflake snowflake;
  29. public static Snowflake Instance()
  30. {
  31. if (snowflake == null)
  32. snowflake = new Snowflake();
  33. return snowflake;
  34. }
  35. private Snowflake()
  36. {
  37. Snowflakes(0L, -1);
  38. }
  39. private Snowflake(long machineId)
  40. {
  41. Snowflakes(machineId, -1);
  42. }
  43. private Snowflake(long machineId, long datacenterId)
  44. {
  45. Snowflakes(machineId, datacenterId);
  46. }
  47. private void Snowflakes(long machineId, long datacenterId)
  48. {
  49. if (machineId >= 0)
  50. {
  51. if (machineId > maxMachineId)
  52. {
  53. throw new Exception("机器码ID非法");
  54. }
  55. Snowflake.machineId = machineId;
  56. }
  57. if (datacenterId >= 0)
  58. {
  59. if (datacenterId > maxDatacenterId)
  60. {
  61. throw new Exception("数据中心ID非法");
  62. }
  63. Snowflake.datacenterId = datacenterId;
  64. }
  65. }
  66. /// <summary>
  67. /// 生成当前时间戳
  68. /// </summary>
  69. /// <returns>毫秒</returns>
  70. private static long GetTimestamp()
  71. {
  72. return (long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds;
  73. }
  74. /// <summary>
  75. /// 获取下一微秒时间戳
  76. /// </summary>
  77. /// <param name="lastTimestamp"></param>
  78. /// <returns></returns>
  79. private static long GetNextTimestamp(long lastTimestamp)
  80. {
  81. long timestamp = GetTimestamp();
  82. if (timestamp <= lastTimestamp)
  83. {
  84. timestamp = GetTimestamp();
  85. }
  86. return timestamp;
  87. }
  88. /// <summary>
  89. /// 获取长整形的ID
  90. /// </summary>
  91. /// <returns></returns>
  92. public long GetId()
  93. {
  94. lock (syncRoot)
  95. {
  96. long timestamp = GetTimestamp();
  97. if (Snowflake.lastTimestamp == timestamp)
  98. { //同一微秒中生成ID
  99. sequence = (sequence + 1) & sequenceMask; //用&运算计算该微秒内产生的计数是否已经到达上限
  100. if (sequence == 0)
  101. {
  102. //一微妙内产生的ID计数已达上限,等待下一微妙
  103. timestamp = GetNextTimestamp(Snowflake.lastTimestamp);
  104. }
  105. }
  106. else
  107. {
  108. //不同微秒生成ID
  109. sequence = 0L;
  110. }
  111. if (timestamp < lastTimestamp)
  112. {
  113. throw new Exception("时间戳比上一次生成ID时时间戳还小,故异常");
  114. }
  115. Snowflake.lastTimestamp = timestamp; //把当前时间戳保存为最后生成ID的时间戳
  116. long Id = ((timestamp - twepoch) << (int)timestampLeftShift)
  117. | (datacenterId << (int)datacenterIdShift)
  118. | (machineId << (int)machineIdShift)
  119. | sequence;
  120. return Id;
  121. }
  122. }
  123. /// <summary>
  124. /// 加前缀的随机数
  125. /// </summary>
  126. /// <param name="pre"></param>
  127. /// <returns></returns>
  128. public string GetId(string prefix)
  129. {
  130. return prefix + this.GetId().ToString();
  131. }
  132. }
  133. }