Sequence.java 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. /**
  2. * Copyright (c) 2011-2020, hubin (jobob@qq.com).
  3. * <p>
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. * <p>
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. * <p>
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.baomidou.mybatisplus.toolkit;
  17. import java.lang.management.ManagementFactory;
  18. import java.net.InetAddress;
  19. import java.net.NetworkInterface;
  20. import java.util.concurrent.ThreadLocalRandom;
  21. import org.apache.ibatis.logging.Log;
  22. import org.apache.ibatis.logging.LogFactory;
  23. import com.baomidou.mybatisplus.exceptions.MybatisPlusException;
  24. /**
  25. * <p>
  26. * 分布式高效有序ID生产黑科技(sequence) <br>
  27. * 优化开源项目:http://git.oschina.net/yu120/sequence
  28. * </p>
  29. *
  30. * @author hubin
  31. * @date 2016-08-18
  32. */
  33. public class Sequence {
  34. private static final Log logger = LogFactory.getLog(Sequence.class);
  35. /* 时间起始标记点,作为基准,一般取系统的最近时间(一旦确定不能变动) */
  36. private final long twepoch = 1288834974657L;
  37. private final long workerIdBits = 5L;/* 机器标识位数 */
  38. private final long datacenterIdBits = 5L;
  39. private final long maxWorkerId = -1L ^ (-1L << workerIdBits);
  40. private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
  41. private final long sequenceBits = 12L;/* 毫秒内自增位 */
  42. private final long workerIdShift = sequenceBits;
  43. private final long datacenterIdShift = sequenceBits + workerIdBits;
  44. /* 时间戳左移动位 */
  45. private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
  46. private final long sequenceMask = -1L ^ (-1L << sequenceBits);
  47. private long workerId;
  48. /* 数据标识id部分 */
  49. private long datacenterId;
  50. private long sequence = 0L;/* 0,并发控制 */
  51. private long lastTimestamp = -1L;/* 上次生产id时间戳 */
  52. public Sequence() {
  53. this.datacenterId = getDatacenterId(maxDatacenterId);
  54. this.workerId = getMaxWorkerId(datacenterId, maxWorkerId);
  55. }
  56. /**
  57. * @param workerId 工作机器ID
  58. * @param datacenterId 序列号
  59. */
  60. public Sequence(long workerId, long datacenterId) {
  61. if (workerId > maxWorkerId || workerId < 0) {
  62. throw new MybatisPlusException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
  63. }
  64. if (datacenterId > maxDatacenterId || datacenterId < 0) {
  65. throw new MybatisPlusException(
  66. String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
  67. }
  68. this.workerId = workerId;
  69. this.datacenterId = datacenterId;
  70. }
  71. /**
  72. * <p>
  73. * 获取 maxWorkerId
  74. * </p>
  75. */
  76. protected static long getMaxWorkerId(long datacenterId, long maxWorkerId) {
  77. StringBuilder mpid = new StringBuilder();
  78. mpid.append(datacenterId);
  79. String name = ManagementFactory.getRuntimeMXBean().getName();
  80. if (StringUtils.isNotEmpty(name)) {
  81. /*
  82. * GET jvmPid
  83. */
  84. mpid.append(name.split("@")[0]);
  85. }
  86. /*
  87. * MAC + PID 的 hashcode 获取16个低位
  88. */
  89. return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1);
  90. }
  91. /**
  92. * <p>
  93. * 数据标识id部分
  94. * </p>
  95. */
  96. protected static long getDatacenterId(long maxDatacenterId) {
  97. long id = 0L;
  98. try {
  99. InetAddress ip = InetAddress.getLocalHost();
  100. NetworkInterface network = NetworkInterface.getByInetAddress(ip);
  101. if (network == null) {
  102. id = 1L;
  103. } else {
  104. byte[] mac = network.getHardwareAddress();
  105. if (null != mac) {
  106. id = ((0x000000FF & (long) mac[mac.length - 1]) | (0x0000FF00 & (((long) mac[mac.length - 2]) << 8))) >> 6;
  107. id = id % (maxDatacenterId + 1);
  108. }
  109. }
  110. } catch (Exception e) {
  111. logger.warn(" getDatacenterId: " + e.getMessage());
  112. }
  113. return id;
  114. }
  115. /**
  116. * 获取下一个ID
  117. *
  118. * @return
  119. */
  120. public synchronized long nextId() {
  121. long timestamp = timeGen();
  122. if (timestamp < lastTimestamp) {//闰秒
  123. long offset = lastTimestamp - timestamp;
  124. if (offset <= 5) {
  125. try {
  126. wait(offset << 1);
  127. timestamp = timeGen();
  128. if (timestamp < lastTimestamp) {
  129. throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", offset));
  130. }
  131. } catch (Exception e) {
  132. throw new RuntimeException(e);
  133. }
  134. } else {
  135. throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", offset));
  136. }
  137. }
  138. if (lastTimestamp == timestamp) {
  139. // 相同毫秒内,序列号自增
  140. sequence = (sequence + 1) & sequenceMask;
  141. if (sequence == 0) {
  142. // 同一毫秒的序列数已经达到最大
  143. timestamp = tilNextMillis(lastTimestamp);
  144. }
  145. } else {
  146. // 不同毫秒内,序列号置为 1 - 3 随机数
  147. sequence = ThreadLocalRandom.current().nextLong(1, 3);
  148. }
  149. lastTimestamp = timestamp;
  150. return ((timestamp - twepoch) << timestampLeftShift) // 时间戳部分
  151. | (datacenterId << datacenterIdShift) // 数据中心部分
  152. | (workerId << workerIdShift) // 机器标识部分
  153. | sequence; // 序列号部分
  154. }
  155. protected long tilNextMillis(long lastTimestamp) {
  156. long timestamp = timeGen();
  157. while (timestamp <= lastTimestamp) {
  158. timestamp = timeGen();
  159. }
  160. return timestamp;
  161. }
  162. protected long timeGen() {
  163. return SystemClock.now();
  164. }
  165. }