IdWorker.java 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. package com.upload.config;
  2. import java.lang.management.ManagementFactory;
  3. import java.net.InetAddress;
  4. import java.net.NetworkInterface;
  5. /**
  6. * <p>名称:IdWorker.java</p>
  7. * <p>描述:分布式自增长ID</p>
  8. * <pre>
  9. * Twitter的 Snowflake JAVA实现方案
  10. * </pre>
  11. * 核心代码为其IdWorker这个类实现,其原理结构如下,我分别用一个0表示一位,用—分割开部分的作用:
  12. * 1||0---0000000000 0000000000 0000000000 0000000000 0 --- 00000 ---00000 ---000000000000
  13. * 在上面的字符串中,第一位为未使用(实际上也可作为long的符号位),接下来的41位为毫秒级时间,
  14. * 然后5位dataCenter标识位,5位机器ID(并不算标识符,实际是为线程标识),
  15. * 然后12位该毫秒内的当前毫秒内的计数,加起来刚好64位,为一个Long型。
  16. * 这样的好处是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由dataCenter和机器ID作区分),
  17. * 并且效率较高,经测试,snowflake每秒能够产生26万ID左右,完全满足需要。
  18. * <p>
  19. * 64位ID (42(毫秒)+5(机器ID)+5(业务编码)+12(重复累加))
  20. *
  21. * @author Polim
  22. */
  23. public class IdWorker {
  24. // 时间起始标记点,作为基准,一般取系统的最近时间(一旦确定不能变动)
  25. private final static long twepoch = 1288834974657L;
  26. // 机器标识位数
  27. private final static long workerIdBits = 5L;
  28. // 数据中心标识位数
  29. private final static long datacenterIdBits = 5L;
  30. // 机器ID最大值
  31. private final static long maxWorkerId = ~(-1L << workerIdBits);
  32. // 数据中心ID最大值
  33. private final static long maxDatacenterId = ~(-1L << datacenterIdBits);
  34. // 毫秒内自增位
  35. private final static long sequenceBits = 12L;
  36. // 机器ID偏左移12位
  37. private final static long workerIdShift = sequenceBits;
  38. // 数据中心ID左移17位
  39. private final static long datacenterIdShift = sequenceBits + workerIdBits;
  40. // 时间毫秒左移22位
  41. private final static long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
  42. private final static long sequenceMask = ~(-1L << sequenceBits);
  43. /* 上次生产id时间戳 */
  44. private static long lastTimestamp = -1L;
  45. // 0,并发控制
  46. private long sequence = 0L;
  47. private final long workerId;
  48. // 数据标识id部分
  49. private final long dataCenterId;
  50. public IdWorker() {
  51. this.dataCenterId = getDataCenterId(maxDatacenterId);
  52. this.workerId = getMaxWorkerId(dataCenterId, maxWorkerId);
  53. }
  54. /**
  55. * @param workerId 工作机器ID
  56. * @param dataCenterId 序列号
  57. */
  58. public IdWorker(long workerId, long dataCenterId) {
  59. if (workerId > maxWorkerId || workerId < 0) {
  60. throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
  61. }
  62. if (dataCenterId > maxDatacenterId || dataCenterId < 0) {
  63. throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
  64. }
  65. this.workerId = workerId;
  66. this.dataCenterId = dataCenterId;
  67. }
  68. /**
  69. * 获取下一个ID
  70. *
  71. * @return
  72. */
  73. public synchronized long nextId() {
  74. long timestamp = timeGen();
  75. if (timestamp < lastTimestamp) {
  76. throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
  77. }
  78. if (lastTimestamp == timestamp) {
  79. // 当前毫秒内,则+1
  80. sequence = (sequence + 1) & sequenceMask;
  81. if (sequence == 0) {
  82. // 当前毫秒内计数满了,则等待下一秒
  83. timestamp = tilNextMillis(lastTimestamp);
  84. }
  85. } else {
  86. sequence = 0L;
  87. }
  88. lastTimestamp = timestamp;
  89. // ID偏移组合生成最终的ID,并返回ID
  90. long nextId = ((timestamp - twepoch) << timestampLeftShift)
  91. | (dataCenterId << datacenterIdShift)
  92. | (workerId << workerIdShift) | sequence;
  93. return nextId;
  94. }
  95. private long tilNextMillis(final long lastTimestamp) {
  96. long timestamp = this.timeGen();
  97. while (timestamp <= lastTimestamp) {
  98. timestamp = this.timeGen();
  99. }
  100. return timestamp;
  101. }
  102. private long timeGen() {
  103. return System.currentTimeMillis();
  104. }
  105. /**
  106. * <p>
  107. * 获取 maxWorkerId
  108. * </p>
  109. */
  110. protected static long getMaxWorkerId(long dataCenterId, long maxWorkerId) {
  111. StringBuffer mpid = new StringBuffer();
  112. mpid.append(dataCenterId);
  113. String name = ManagementFactory.getRuntimeMXBean().getName();
  114. if (!name.isEmpty()) {
  115. /*
  116. * GET jvmPid
  117. */
  118. mpid.append(name.split("@")[0]);
  119. }
  120. /*
  121. * MAC + PID 的 hashcode 获取16个低位
  122. */
  123. return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1);
  124. }
  125. /**
  126. * <p>
  127. * 数据标识id部分
  128. * </p>
  129. */
  130. protected static long getDataCenterId(long maxDataCenterId) {
  131. long id = 0L;
  132. try {
  133. InetAddress ip = InetAddress.getLocalHost();
  134. NetworkInterface network = NetworkInterface.getByInetAddress(ip);
  135. if (network == null) {
  136. id = 1L;
  137. } else {
  138. byte[] mac = network.getHardwareAddress();
  139. id = ((0x000000FF & (long) mac[mac.length - 1])
  140. | (0x0000FF00 & (((long) mac[mac.length - 2]) << 8))) >> 6;
  141. id = id % (maxDataCenterId + 1);
  142. }
  143. } catch (Exception e) {
  144. System.out.println(" getDataCenterId: " + e.getMessage());
  145. }
  146. return id;
  147. }
  148. }