代码——雪花算法的默认实现(截取自Shardingsphere)

返回的是64位long型数值,末尾12位是自增序列,最大支持4096,逻辑上是每毫秒的id最大生成数量;末尾12到22位的10bit是机器id;前面43位是时间戳(ms)左移22位得到的;最前面1位是保留位(因为整形的二进制首位默认就是表示正负用的)。

  1. /*
  2. * Copyright 2016-2018 shardingsphere.io.
  3. * <p>
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. * </p>
  16. */
  17. package io.shardingsphere.core.keygen;
  18. import com.google.common.base.Preconditions;
  19. import lombok.Setter;
  20. import lombok.SneakyThrows;
  21. import java.util.Calendar;
  22. /**
  23. * Default distributed primary key generator.
  24. *
  25. * <p>
  26. * Use snowflake algorithm. Length is 64 bit.
  27. * </p>
  28. *
  29. * <pre>
  30. * 1bit sign bit.
  31. * 41bits timestamp offset from 2016.11.01(ShardingSphere distributed primary key published data) to now.
  32. * 10bits worker process id.
  33. * 12bits auto increment offset in one mills
  34. * </pre>
  35. *
  36. * <p>
  37. * Call @{@code DefaultKeyGenerator.setWorkerId} to set worker id, default value is 0.
  38. * </p>
  39. *
  40. * <p>
  41. * Call @{@code DefaultKeyGenerator.setMaxTolerateTimeDifferenceMilliseconds} to set max tolerate time difference milliseconds, default value is 0.
  42. * </p>
  43. *
  44. * @author gaohongtao
  45. */
  46. public final class DefaultKeyGenerator implements KeyGenerator {
  47. public static final long EPOCH;
  48. private static final long SEQUENCE_BITS = 12L;
  49. private static final long WORKER_ID_BITS = 10L;
  50. private static final long SEQUENCE_MASK = (1 << SEQUENCE_BITS) - 1;
  51. private static final long WORKER_ID_LEFT_SHIFT_BITS = SEQUENCE_BITS;
  52. private static final long TIMESTAMP_LEFT_SHIFT_BITS = WORKER_ID_LEFT_SHIFT_BITS + WORKER_ID_BITS;
  53. private static final long WORKER_ID_MAX_VALUE = 1L << WORKER_ID_BITS;
  54. @Setter
  55. private static TimeService timeService = new TimeService();
  56. private static long workerId;
  57. private static int maxTolerateTimeDifferenceMilliseconds = 10;
  58. static {
  59. Calendar calendar = Calendar.getInstance();
  60. calendar.set(2016, Calendar.NOVEMBER, 1);
  61. calendar.set(Calendar.HOUR_OF_DAY, 0);
  62. calendar.set(Calendar.MINUTE, 0);
  63. calendar.set(Calendar.SECOND, 0);
  64. calendar.set(Calendar.MILLISECOND, 0);
  65. EPOCH = calendar.getTimeInMillis();
  66. }
  67. private byte sequenceOffset;
  68. private long sequence;
  69. private long lastMilliseconds;
  70. /**
  71. * Set work process id.
  72. *
  73. * @param workerId work process id
  74. */
  75. public static void setWorkerId(final long workerId) {
  76. Preconditions.checkArgument(workerId >= 0L && workerId < WORKER_ID_MAX_VALUE);
  77. DefaultKeyGenerator.workerId = workerId;
  78. }
  79. /**
  80. * Set max tolerate time difference milliseconds.
  81. *
  82. * @param maxTolerateTimeDifferenceMilliseconds max tolerate time difference milliseconds
  83. */
  84. public static void setMaxTolerateTimeDifferenceMilliseconds(final int maxTolerateTimeDifferenceMilliseconds) {
  85. DefaultKeyGenerator.maxTolerateTimeDifferenceMilliseconds = maxTolerateTimeDifferenceMilliseconds;
  86. }
  87. /**
  88. * Generate key.
  89. *
  90. * @return key type is @{@link Long}.
  91. */
  92. @Override
  93. public synchronized Number generateKey() {
  94. long currentMilliseconds = timeService.getCurrentMillis();
  95. if (waitTolerateTimeDifferenceIfNeed(currentMilliseconds)) {
  96. currentMilliseconds = timeService.getCurrentMillis();
  97. }
  98. if (lastMilliseconds == currentMilliseconds) {
  99. if (0L == (sequence = (sequence + 1) & SEQUENCE_MASK)) {
  100. currentMilliseconds = waitUntilNextTime(currentMilliseconds);
  101. }
  102. } else {
  103. vibrateSequenceOffset();
  104. sequence = sequenceOffset;
  105. }
  106. lastMilliseconds = currentMilliseconds;
  107. return ((currentMilliseconds - EPOCH) << TIMESTAMP_LEFT_SHIFT_BITS) | (workerId << WORKER_ID_LEFT_SHIFT_BITS) | sequence;
  108. }
  109. @SneakyThrows
  110. private boolean waitTolerateTimeDifferenceIfNeed(final long currentMilliseconds) {
  111. if (lastMilliseconds <= currentMilliseconds) {
  112. return false;
  113. }
  114. long timeDifferenceMilliseconds = lastMilliseconds - currentMilliseconds;
  115. Preconditions.checkState(timeDifferenceMilliseconds < maxTolerateTimeDifferenceMilliseconds,
  116. "Clock is moving backwards, last time is %d milliseconds, current time is %d milliseconds", lastMilliseconds, currentMilliseconds);
  117. Thread.sleep(timeDifferenceMilliseconds);
  118. return true;
  119. }
  120. private long waitUntilNextTime(final long lastTime) {
  121. long result = timeService.getCurrentMillis();
  122. while (result <= lastTime) {
  123. result = timeService.getCurrentMillis();
  124. }
  125. return result;
  126. }
  127. private void vibrateSequenceOffset() {
  128. sequenceOffset = (byte) (~sequenceOffset & 1);
  129. }
  130. }