该部分代码由mybatis-plus提供

    工具依赖

    1. <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
    2. <dependency>
    3. <groupId>org.apache.commons</groupId>
    4. <artifactId>commons-lang3</artifactId>
    5. <version>3.11</version>
    6. </dependency>
    1. package com.example.demo.雪花算法;
    2. import lombok.extern.slf4j.Slf4j;
    3. import org.apache.commons.lang3.StringUtils;
    4. import org.springframework.util.Assert;
    5. import java.lang.management.ManagementFactory;
    6. import java.net.InetAddress;
    7. import java.net.NetworkInterface;
    8. import java.util.concurrent.ThreadLocalRandom;
    9. @Slf4j
    10. public class Sequence {
    11. /**
    12. * 时间起始标记点,作为基准,一般取系统的最近时间(一旦确定不能变动)
    13. */
    14. private final long twepoch = 1288834974657L;
    15. /**
    16. * 机器标识位数
    17. */
    18. private final long workerIdBits = 5L;
    19. private final long datacenterIdBits = 5L;
    20. private final long maxWorkerId = -1L ^ (-1L << workerIdBits);
    21. private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
    22. /**
    23. * 毫秒内自增位
    24. */
    25. private final long sequenceBits = 12L;
    26. private final long workerIdShift = sequenceBits;
    27. private final long datacenterIdShift = sequenceBits + workerIdBits;
    28. /**
    29. * 时间戳左移动位
    30. */
    31. private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
    32. private final long sequenceMask = -1L ^ (-1L << sequenceBits);
    33. private final long workerId;
    34. /**
    35. * 数据标识 ID 部分
    36. */
    37. private final long datacenterId;
    38. /**
    39. * 并发控制
    40. */
    41. private long sequence = 0L;
    42. /**
    43. * 上次生产 ID 时间戳
    44. */
    45. private long lastTimestamp = -1L;
    46. public Sequence() {
    47. this.datacenterId = getDatacenterId(maxDatacenterId);
    48. this.workerId = getMaxWorkerId(datacenterId, maxWorkerId);
    49. }
    50. /**
    51. * 有参构造器
    52. *
    53. * @param workerId 工作机器 ID
    54. * @param datacenterId 序列号
    55. */
    56. public Sequence(long workerId, long datacenterId) {
    57. Assert.isTrue(!(workerId > maxWorkerId || workerId < 0),
    58. String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
    59. Assert.isTrue(!(datacenterId > maxDatacenterId || datacenterId < 0),
    60. String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
    61. this.workerId = workerId;
    62. this.datacenterId = datacenterId;
    63. }
    64. /**
    65. * 获取 maxWorkerId
    66. */
    67. protected static long getMaxWorkerId(long datacenterId, long maxWorkerId) {
    68. StringBuilder mpid = new StringBuilder();
    69. mpid.append(datacenterId);
    70. String name = ManagementFactory.getRuntimeMXBean().getName();
    71. if (StringUtils.isNotBlank(name)) {
    72. /*
    73. * GET jvmPid
    74. */
    75. mpid.append(name.split("@")[0]);
    76. }
    77. /*
    78. * MAC + PID 的 hashcode 获取16个低位
    79. */
    80. return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1);
    81. }
    82. /**
    83. * 数据标识id部分
    84. */
    85. protected static long getDatacenterId(long maxDatacenterId) {
    86. long id = 0L;
    87. try {
    88. InetAddress ip = InetAddress.getLocalHost();
    89. NetworkInterface network = NetworkInterface.getByInetAddress(ip);
    90. if (network == null) {
    91. id = 1L;
    92. } else {
    93. byte[] mac = network.getHardwareAddress();
    94. if (null != mac) {
    95. id = ((0x000000FF & (long) mac[mac.length - 2]) | (0x0000FF00 & (((long) mac[mac.length - 1]) << 8))) >> 6;
    96. id = id % (maxDatacenterId + 1);
    97. }
    98. }
    99. } catch (Exception e) {
    100. log.warn(" getDatacenterId: " + e.getMessage());
    101. }
    102. return id;
    103. }
    104. /**
    105. * 获取下一个 ID
    106. *
    107. * @return 下一个 ID
    108. */
    109. public synchronized long nextId() {
    110. long timestamp = timeGen();
    111. //闰秒
    112. if (timestamp < lastTimestamp) {
    113. long offset = lastTimestamp - timestamp;
    114. if (offset <= 5) {
    115. try {
    116. wait(offset << 1);
    117. timestamp = timeGen();
    118. if (timestamp < lastTimestamp) {
    119. throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", offset));
    120. }
    121. } catch (Exception e) {
    122. throw new RuntimeException(e);
    123. }
    124. } else {
    125. throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", offset));
    126. }
    127. }
    128. if (lastTimestamp == timestamp) {
    129. // 相同毫秒内,序列号自增
    130. sequence = (sequence + 1) & sequenceMask;
    131. if (sequence == 0) {
    132. // 同一毫秒的序列数已经达到最大
    133. timestamp = tilNextMillis(lastTimestamp);
    134. }
    135. } else {
    136. // 不同毫秒内,序列号置为 1 - 3 随机数
    137. sequence = ThreadLocalRandom.current().nextLong(1, 3);
    138. }
    139. lastTimestamp = timestamp;
    140. // 时间戳部分 | 数据中心部分 | 机器标识部分 | 序列号部分
    141. return ((timestamp - twepoch) << timestampLeftShift)
    142. | (datacenterId << datacenterIdShift)
    143. | (workerId << workerIdShift)
    144. | sequence;
    145. }
    146. protected long tilNextMillis(long lastTimestamp) {
    147. long timestamp = timeGen();
    148. while (timestamp <= lastTimestamp) {
    149. timestamp = timeGen();
    150. }
    151. return timestamp;
    152. }
    153. protected long timeGen() {
    154. return SystemClock.now();
    155. }
    156. }
    1. package com.example.demo.雪花算法;
    2. import java.sql.Timestamp;
    3. import java.util.concurrent.Executors;
    4. import java.util.concurrent.ScheduledExecutorService;
    5. import java.util.concurrent.TimeUnit;
    6. import java.util.concurrent.atomic.AtomicLong;
    7. public class SystemClock {
    8. private final long period;
    9. private final AtomicLong now;
    10. private SystemClock(long period) {
    11. this.period = period;
    12. this.now = new AtomicLong(System.currentTimeMillis());
    13. scheduleClockUpdating();
    14. }
    15. private static SystemClock instance() {
    16. return InstanceHolder.INSTANCE;
    17. }
    18. public static long now() {
    19. return instance().currentTimeMillis();
    20. }
    21. public static String nowDate() {
    22. return new Timestamp(instance().currentTimeMillis()).toString();
    23. }
    24. private void scheduleClockUpdating() {
    25. ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(runnable -> {
    26. Thread thread = new Thread(runnable, "System Clock");
    27. thread.setDaemon(true);
    28. return thread;
    29. });
    30. scheduler.scheduleAtFixedRate(() -> now.set(System.currentTimeMillis()), period, period, TimeUnit.MILLISECONDS);
    31. }
    32. private long currentTimeMillis() {
    33. return now.get();
    34. }
    35. private static class InstanceHolder {
    36. public static final SystemClock INSTANCE = new SystemClock(1);
    37. }
    38. }