工具类: 


   
  1. package com.ihrm.common.utils;
  2. import java.lang.management.ManagementFactory;
  3. import java.net.InetAddress;
  4. import java.net.NetworkInterface;
  5. //雪花算法代码实现
  6. public class IdWorker {
  7. // 时间起始标记点,作为基准,一般取系统的最近时间(一旦确定不能变动)
  8. private final static long twepoch = 1288834974657L;
  9. // 机器标识位数
  10. private final static long workerIdBits = 5L;
  11. // 数据中心标识位数
  12. private final static long datacenterIdBits = 5L;
  13. // 机器ID最大值
  14. private final static long maxWorkerId = - 1L ^ (- 1L << workerIdBits);
  15. // 数据中心ID最大值
  16. private final static long maxDatacenterId = - 1L ^ (- 1L << datacenterIdBits);
  17. // 毫秒内自增位
  18. private final static long sequenceBits = 12L;
  19. // 机器ID偏左移12位
  20. private final static long workerIdShift = sequenceBits;
  21. // 数据中心ID左移17位
  22. private final static long datacenterIdShift = sequenceBits + workerIdBits;
  23. // 时间毫秒左移22位
  24. private final static long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
  25. private final static long sequenceMask = - 1L ^ (- 1L << sequenceBits);
  26. /* 上次生产id时间戳 */
  27. private static long lastTimestamp = - 1L;
  28. // 0,并发控制
  29. private long sequence = 0L;
  30. private final long workerId;
  31. // 数据标识id部分
  32. private final long datacenterId;
  33. public IdWorker(){
  34. this.datacenterId = getDatacenterId(maxDatacenterId);
  35. this.workerId = getMaxWorkerId(datacenterId, maxWorkerId);
  36. }
  37. /**
  38. * @param workerId
  39. * 工作机器ID
  40. * @param datacenterId
  41. * 序列号
  42. */
  43. public IdWorker(long workerId, long datacenterId) {
  44. if (workerId > maxWorkerId || workerId < 0) {
  45. throw new IllegalArgumentException(String.format( "worker Id can't be greater than %d or less than 0", maxWorkerId));
  46. }
  47. if (datacenterId > maxDatacenterId || datacenterId < 0) {
  48. throw new IllegalArgumentException(String.format( "datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
  49. }
  50. this.workerId = workerId;
  51. this.datacenterId = datacenterId;
  52. }
  53. /**
  54. * 获取下一个ID
  55. *
  56. * @return
  57. */
  58. public synchronized long nextId() {
  59. long timestamp = timeGen();
  60. if (timestamp < lastTimestamp) {
  61. throw new RuntimeException(String.format( "Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
  62. }
  63. if (lastTimestamp == timestamp) {
  64. // 当前毫秒内,则+1
  65. sequence = (sequence + 1) & sequenceMask;
  66. if (sequence == 0) {
  67. // 当前毫秒内计数满了,则等待下一秒
  68. timestamp = tilNextMillis(lastTimestamp);
  69. }
  70. } else {
  71. sequence = 0L;
  72. }
  73. lastTimestamp = timestamp;
  74. // ID偏移组合生成最终的ID,并返回ID
  75. long nextId = ((timestamp - twepoch) << timestampLeftShift)
  76. | (datacenterId << datacenterIdShift)
  77. | (workerId << workerIdShift) | sequence;
  78. return nextId;
  79. }
  80. private long tilNextMillis(final long lastTimestamp) {
  81. long timestamp = this.timeGen();
  82. while (timestamp <= lastTimestamp) {
  83. timestamp = this.timeGen();
  84. }
  85. return timestamp;
  86. }
  87. private long timeGen() {
  88. return System.currentTimeMillis();
  89. }
  90. /**
  91. * <p>
  92. * 获取 maxWorkerId
  93. * </p>
  94. */
  95. protected static long getMaxWorkerId(long datacenterId, long maxWorkerId) {
  96. StringBuffer mpid = new StringBuffer();
  97. mpid.append(datacenterId);
  98. String name = ManagementFactory.getRuntimeMXBean().getName();
  99. if (!name.isEmpty()) {
  100. /*
  101. * GET jvmPid
  102. */
  103. mpid.append(name.split( "@")[ 0]);
  104. }
  105. /*
  106. * MAC + PID 的 hashcode 获取16个低位
  107. */
  108. return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1);
  109. }
  110. /**
  111. * <p>
  112. * 数据标识id部分
  113. * </p>
  114. */
  115. protected static long getDatacenterId(long maxDatacenterId) {
  116. long id = 0L;
  117. try {
  118. InetAddress ip = InetAddress.getLocalHost();
  119. NetworkInterface network = NetworkInterface.getByInetAddress(ip);
  120. if (network == null) {
  121. id = 1L;
  122. } else {
  123. byte[] mac = network.getHardwareAddress();
  124. id = (( 0x000000FF & ( long) mac[mac.length - 1])
  125. | ( 0x0000FF00 & ((( long) mac[mac.length - 2]) << 8))) >> 6;
  126. id = id % (maxDatacenterId + 1);
  127. }
  128. } catch (Exception e) {
  129. System.out.println( " getDatacenterId: " + e.getMessage());
  130. }
  131. return id;
  132. }
  133. }

使用:


   
  1. IdWorker idWorker = new IdWorker();
  2. long id = idWorker.nextId();

发布评论
IT序号网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!

JPA主键生成策略知识解答
你是第一个吃螃蟹的人
发表评论

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。