1. package com.aiyusheng.shopping.util;
  2.  
  3. import java.lang.management.ManagementFactory;
  4. import java.net.InetAddress;
  5. import java.net.NetworkInterface;
  6. import java.text.SimpleDateFormat;
  7. import java.util.Date;
  8.  
  9. /**
  10. * <p>名称:IdWorker.java</p>
  11. * <p>描述:分布式自增长ID</p>
  12. * <pre>
  13. * Twitter的 Snowflake JAVA实现方案
  14. * </pre>
  15. * 核心代码为其IdWorker这个类实现,其原理结构如下,我分别用一个0表示一位,用—分割开部分的作用:
  16. * 1||0---0000000000 0000000000 0000000000 0000000000 0 --- 00000 ---00000 ---000000000000
  17. * 在上面的字符串中,第一位为未使用(实际上也可作为long的符号位),接下来的41位为毫秒级时间,
  18. * 然后5位datacenter标识位,5位机器ID(并不算标识符,实际是为线程标识),
  19. * 然后12位该毫秒内的当前毫秒内的计数,加起来刚好64位,为一个Long型。
  20. * 这样的好处是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由datacenter和机器ID作区分),
  21. * 并且效率较高,经测试,snowflake每秒能够产生26万ID左右,完全满足需要。
  22. * <p>
  23. * 64位ID (42(毫秒)+5(机器ID)+5(业务编码)+12(重复累加))
  24. *
  25. * @author Polim
  26. */
  27. public class IdWorker {
  28. // 时间起始标记点,作为基准,一般取系统的最近时间(一旦确定不能变动)
  29. private final static long TWEPOCH= 1288834974657L;
  30. // 机器标识位数
  31. private final static long WORKDER_ID_BITS = 5L;
  32. // 数据中心标识位数
  33. private final static long DATACENTER_ID_BITS = 5L;
  34. // 机器ID最大值
  35. private final static long MAX_WORKDER_ID= -1L ^ (-1L << WORKDER_ID_BITS);
  36. // 数据中心ID最大值
  37. private final static long MAX_DATACENTER_ID= -1L ^ (-1L << DATACENTER_ID_BITS);
  38. // 毫秒内自增位
  39. private final static long SEQUENCE_BITS= 12L;
  40. // 机器ID偏左移12位
  41. private final static long WORKDER_ID_SHIFT= SEQUENCE_BITS;
  42. // 数据中心ID左移17位
  43. private final static long DATACENTER_ID_SHIFT= SEQUENCE_BITS + WORKDER_ID_BITS;
  44. // 时间毫秒左移22位
  45. private final static long TIMESTAMP_LEFT_SHIFT = SEQUENCE_BITS + WORKDER_ID_BITS + SEQUENCE_BITS;
  46.  
  47. private final static long SEQUENCE_MASK= -1L ^ (-1L << SEQUENCE_BITS);
  48. /* 上次生产id时间戳 */
  49. private static long lastTimestamp = -1L;
  50. // 0,并发控制
  51. private long sequence = 0L;
  52.  
  53. private final long workerId;
  54. // 数据标识id部分
  55. private final long datacenterId;
  56.  
  57. public IdWorker(){
  58. this.datacenterId = getDatacenterId(MAX_DATACENTER_ID);
  59. this.workerId = getMaxWorkerId(datacenterId, MAX_WORKDER_ID);
  60. }
  61. /**
  62. * @param workerId
  63. * 工作机器ID
  64. * @param datacenterId
  65. * 序列号
  66. */
  67. public IdWorker(long workerId, long datacenterId) {
  68. if (workerId > MAX_WORKDER_ID || workerId < 0) {
  69. throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", MAX_WORKDER_ID));
  70. }
  71. if (datacenterId > MAX_WORKDER_ID || datacenterId < 0) {
  72. throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", MAX_DATACENTER_ID));
  73. }
  74. this.workerId = workerId;
  75. this.datacenterId = datacenterId;
  76. }
  77. /**
  78. * 获取下一个ID
  79. *
  80. * @return
  81. */
  82. public synchronized long nextId() {
  83. long timestamp = timeGen();
  84. if (timestamp < lastTimestamp) {
  85. throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
  86. }
  87.  
  88. if (lastTimestamp == timestamp) {
  89. // 当前毫秒内,则+1
  90. sequence = (sequence + 1) & SEQUENCE_MASK;
  91. if (sequence == 0) {
  92. // 当前毫秒内计数满了,则等待下一秒
  93. timestamp = tilNextMillis(lastTimestamp);
  94. }
  95. } else {
  96. sequence = 0L;
  97. }
  98. lastTimestamp = timestamp;
  99. // ID偏移组合生成最终的ID,并返回ID
  100. long nextId = ((timestamp - TWEPOCH) << TIMESTAMP_LEFT_SHIFT)
  101. | (datacenterId << DATACENTER_ID_SHIFT)
  102. | (workerId << WORKDER_ID_SHIFT) | sequence;
  103.  
  104. return nextId;
  105. }
  106.  
  107. /**
  108. * 功能描述: 自动补全生成32位
  109. * @Param:
  110. * @Return: java.lang.String
  111. * @Author: chenzhian
  112. * @Date: 2020/12/2 17:24
  113. * @Description:
  114. */
  115. public synchronized String next32Id(){
  116. String Id= nextId()+"";
  117. String nowtime = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
  118. Integer surplusLength=32-Id.length()-nowtime.length();
  119. if(surplusLength>0){
  120. //自动补缺数字
  121. String strsurplus = String.format("%0"+surplusLength+"d", 0);
  122. return nowtime+strsurplus+Id;
  123. }else if(surplusLength==0){
  124. return nowtime+Id;
  125. }else{
  126. return nowtime.substring(0,(nowtime.length()+surplusLength))+Id;
  127. }
  128. }
  129.  
  130. /**
  131. * 阻塞到下一个毫秒,直到获得新的时间戳
  132. * @param lastTimestamp 上次生成ID的时间截
  133. * @return 当前时间戳
  134. */
  135. private long tilNextMillis(final long lastTimestamp) {
  136. long timestamp = this.timeGen();
  137. while (timestamp <= lastTimestamp) {
  138. timestamp = this.timeGen();
  139. }
  140. return timestamp;
  141. }
  142.  
  143. /**
  144. * 返回以毫秒为单位的当前时间
  145. * @return 当前时间(毫秒)
  146. */
  147. private long timeGen() {
  148. return System.currentTimeMillis();
  149. }
  150.  
  151. /**
  152. * <p>
  153. * 获取 maxWorkerId
  154. * </p>
  155. */
  156. protected static long getMaxWorkerId(long datacenterId, long maxWorkerId) {
  157. StringBuffer mpid = new StringBuffer();
  158. mpid.append(datacenterId);
  159. String name = ManagementFactory.getRuntimeMXBean().getName();
  160. if (!name.isEmpty()) {
  161. /*
  162. * GET jvmPid
  163. */
  164. mpid.append(name.split("@")[0]);
  165. }
  166. /*
  167. * MAC + PID 的 hashcode 获取16个低位
  168. */
  169. return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1);
  170. }
  171.  
  172. /**
  173. * <p>
  174. * 数据标识id部分
  175. * </p>
  176. */
  177. protected static long getDatacenterId(long maxDatacenterId) {
  178. long id = 0L;
  179. try {
  180. InetAddress ip = InetAddress.getLocalHost();
  181. NetworkInterface network = NetworkInterface.getByInetAddress(ip);
  182. if (network == null) {
  183. id = 1L;
  184. } else {
  185. byte[] mac = network.getHardwareAddress();
  186. id = ((0x000000FF & (long) mac[mac.length - 1])
  187. | (0x0000FF00 & (((long) mac[mac.length - 2]) << 8))) >> 6;
  188. id = id % (maxDatacenterId + 1);
  189. }
  190. } catch (Exception e) {
  191. System.out.println(" getDatacenterId: " + e.getMessage());
  192. }
  193. return id;
  194. }
  195.  
  196. }
  1. package com.aiyusheng.shopping.config;
  2.  
  3. import org.springframework.boot.context.properties.ConfigurationProperties;
  4.  
  5. @ConfigurationProperties(prefix = "ly.worker")
  6. public class IdWorkerProperties {
  7.  
  8. private long workerId;// 当前机器id
  9.  
  10. private long datacenterId;// 序列号
  11.  
  12. public long getWorkerId() {
  13. return workerId;
  14. }
  15.  
  16. public void setWorkerId(long workerId) {
  17. this.workerId = workerId;
  18. }
  19.  
  20. public long getDatacenterId() {
  21. return datacenterId;
  22. }
  23.  
  24. public void setDatacenterId(long datacenterId) {
  25. this.datacenterId = datacenterId;
  26. }
  27. }
  1. package com.aiyusheng.shopping.config;
  2.  
  3. import com.aiyusheng.shopping.util.IdWorker;
  4. import org.springframework.boot.context.properties.EnableConfigurationProperties;
  5. import org.springframework.context.annotation.Bean;
  6. import org.springframework.context.annotation.Configuration;
  7.  
  8. @Configuration
  9. @EnableConfigurationProperties(IdWorkerProperties.class)
  10. public class IdWorkerConfig {
  11.  
  12. @Bean
  13. public IdWorker idWorker(IdWorkerProperties prop) {
  14. return new IdWorker(prop.getWorkerId(), prop.getDatacenterId());
  15. }
  16. }

配置文件application.properties

  1. ly.worker.workerId=1
  2. ly.worker.datacenterId=1

自己写雪花算法IdWorker的更多相关文章

  1. 分布式id生成器,雪花算法IdWorker

    /** * <p>名称:IdWorker.java</p> * <p>描述:分布式自增长ID</p> * <pre> * Twitter的 ...

  2. 分布式id的生成方式——雪花算法

    雪花算法是twitter开源的一个算法. 由64位0或1组成,其中41位是时间戳,10位工作机器id,12位序列号,该类通过方法nextID()实现id的生成,用Long数据类型去存储. 我们使用id ...

  3. 【Java】分布式自增ID算法---雪花算法 (snowflake,Java版)

    一般情况,实现全局唯一ID,有三种方案,分别是通过中间件方式.UUID.雪花算法. 方案一,通过中间件方式,可以是把数据库或者redis缓存作为媒介,从中间件获取ID.这种呢,优点是可以体现全局的递增 ...

  4. 分布式雪花算法获取id

    实现全局唯一ID 一.采用主键自增 最常见的方式.利用数据库,全数据库唯一. 优点: 1)简单,代码方便,性能可以接受. 2)数字ID天然排序,对分页或者需要排序的结果很有帮助. 缺点: 1)不同数据 ...

  5. 雪花算法(SnowFlake)Java实现

    分布式id生成算法的有很多种,Twitter的SnowFlake就是其中经典的一种. 算法原理 SnowFlake算法生成id的结果是一个64bit大小的整数,它的结构如下图: 1bit,不用,因为二 ...

  6. ID 生成器 雪花算法

    https://blog.csdn.net/wangming520liwei/article/details/80843248 ID 生成器 雪花算法 2018年06月28日 14:58:43 wan ...

  7. 分布式系统-主键唯一id,订单编号生成-雪花算法-SnowFlake

    分布式系统下 我们每台设备(分布式系统-独立的应用空间-或者docker环境) * SnowFlake的优点是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由数据中心ID和机器ID作 ...

  8. 分布式Snowflake雪花算法

    前言 项目中主键ID生成方式比较多,但是哪种方式更能提高的我们的工作效率.项目质量.代码实用性以及健壮性呢,下面作了一下比较,目前雪花算法的优点还是很明显的. 优缺点比较 UUID(缺点:太长.没法排 ...

  9. 一个类似 Twitter 雪花算法 的 连续序号 ID 产生器 SeqIDGenerator

    项目地址 :     https://github.com/kelin-xycs/SeqIDGenerator 今天 QQ 群 里有网友问起产生唯一 ID 的方法 有哪些,  讨论了各种方法 . 有网 ...

随机推荐

  1. python学习番外篇——字符串的数据类型转换及内置方法

    目录 字符串的数据类型转换及内置方法 类型转换 内置方法 优先掌握的方法 需要掌握的方法 strip, lstrip, rstrip lower, upper, islower, isupper 插入 ...

  2. BUUCTF-Web:[GXYCTF2019]Ping Ping Ping

    题目 解题过程 1.题目页面提示?ip=,猜测是让我们把这个当做变量上传参数,由此猜想是命令注入 2.用管道符加上linux常用命令ls(windwos可以尝试dir)试试 所谓管道符(linux)的 ...

  3. OA办公软件篇(三)—审批流

    背景 作用 迭代历程 具体实现 写在最后   背景 在前面两篇文章中,我们分别讲了组织架构和权限管理,今天我们来讲一个跟组织架构关系比较密切的功能-审批流. 审批流,通俗来说就是一个完整的审批流程,是 ...

  4. Golang(go语言)开发环境配置

    VSCode开发环境配置 目录 VSCode开发环境配置 先到VSCode官网去下载适合自己系统的VSCode安装软件 演示在WIndows下 安装使用 演示在Linux(Ubuntu/centos) ...

  5. NLP教程(7) - 问答系统

    作者:韩信子@ShowMeAI 教程地址:http://www.showmeai.tech/tutorials/36 本文地址:http://www.showmeai.tech/article-det ...

  6. 用js给闺女做了一个加减乘除的html

    下班回家用二十分钟给闺女做了一个加减乘除的页面,顺便记录下代码,时间仓促,后期再来修改吧 目录结构 -yq --menu.html --yq.html --yq50.html --yq70.html ...

  7. 基于 Jenkins + Kubernetes + Argo CD 的完整 DevOps 流程记录(1) - 环境部署

    一.环境准备 1.1 镜像仓库 整套 DevOps 流程使用 Harbor 作为内部镜像仓库,所有构建产物(镜像)都会推送到 Harbor,以备后续进行项目部署.Harbor 从 2.x 版本开始支持 ...

  8. Vue 中 watch 的一个坑

    开发所用 Vue 版本 2.6.11 子组件 coma 中两个属性: props: { url: { type: String, default: '' }, oriurl:{ type: Strin ...

  9. 构建第一个模型:KNN算法(Iris_dataset)

    利用鸢尾花数据集完成一个简单的机器学习应用~万丈高楼平地起,虽然很基础,但是还是跟着书敲了一遍代码. 一.模型构建流程 1.获取数据 本次实验的Iris数据集来自skicit-learn的datase ...

  10. ConfigurationManager姿势快闪

    C# ConfigurationManager使用记录 最近一个祖传代码是使用.NET Fx写就的,我在使用控制台程序获取配置时有些折腾. 下面记录一些管理配置文件的姿势: Configuration ...