开箱即用轻量级雪花算法id生成器Java工具类

开箱即用轻量级雪花算法id生成器Java工具类

    • 1.1 背景
    • 1.2 雪花算法id生成器Java工具类

1.1 背景

在 Java后端研发过程中,对于分布式微服务来说,一般需要分布式 id生成.

这里分享一个非常好用且大多数情况下都可用的开箱即用轻量级雪花算法id生成器Java工具类。

这种方式生成的雪花算法生成器生成的唯一主键id,好处是不依赖第三方组件,轻量级,缺点是服务器的时钟不可以回拨,否则可能会造成生成的主键id冲突。

1.2 雪花算法id生成器Java工具类

雪花算法id生成器Java工具类源码

import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;/*** id自增器(雪花算法)* @author renjie* @version 1.0.0*/
public class SnowFlakeUtils {private final static long twepoch = 12888349746579L;/*** 机器标识位数*/private final static long workerIdBits = 5L;/*** 数据中心标识位数*/private final static long datacenterIdBits = 5L;/*** 毫秒内自增位数*/private final static long sequenceBits = 12L;/*** 机器ID偏左移12位*/private final static long workerIdShift = sequenceBits;/*** 数据中心ID左移17位*/private final static long datacenterIdShift = sequenceBits + workerIdBits;/*** 时间毫秒左移22位*/private final static long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;/*** sequence掩码,确保sequnce不会超出上限*/private final static long sequenceMask = -1L ^ (-1L << sequenceBits);/*** 上次时间戳*/private static long lastTimestamp = -1L;/*** 序列*/private long sequence = 0L;/*** 服务器ID*/private long workerId = 1L;private static long workerMask = -1L ^ (-1L << workerIdBits);/*** 进程编码*/private long processId = 1L;private static long processMask = -1L ^ (-1L << datacenterIdBits);private static SnowFlakeUtils snowFlakeUtils = null;static{snowFlakeUtils = new SnowFlakeUtils();}public static synchronized long nextId(){return snowFlakeUtils.getNextId();}private SnowFlakeUtils() {//获取机器编码this.workerId=this.getMachineNum();//获取进程编码RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();this.processId=Long.valueOf(runtimeMXBean.getName().split("@")[0]).longValue();//避免编码超出最大值this.workerId=workerId & workerMask;this.processId=processId & processMask;}public synchronized long getNextId() {//获取时间戳long timestamp = timeGen();//如果时间戳小于上次时间戳则报错if (timestamp < lastTimestamp) {try {throw new Exception("Clock moved backwards.  Refusing to generate id for " + (lastTimestamp - timestamp) + " milliseconds");} catch (Exception e) {e.printStackTrace();}}//如果时间戳与上次时间戳相同if (lastTimestamp == timestamp) {// 当前毫秒内,则+1,与sequenceMask确保sequence不会超出上限sequence = (sequence + 1) & sequenceMask;if (sequence == 0) {// 当前毫秒内计数满了,则等待下一秒timestamp = tilNextMillis(lastTimestamp);}} else {sequence = 0;}lastTimestamp = timestamp;// ID偏移组合生成最终的ID,并返回IDlong nextId = ((timestamp - twepoch) << timestampLeftShift) | (processId << datacenterIdShift) | (workerId << workerIdShift) | sequence;return nextId;}/*** 再次获取时间戳直到获取的时间戳与现有的不同* @param lastTimestamp* @return 下一个时间戳*/private long tilNextMillis(final long lastTimestamp) {long timestamp = this.timeGen();while (timestamp <= lastTimestamp) {timestamp = this.timeGen();}return timestamp;}private long timeGen() {return System.currentTimeMillis();}/*** 获取机器编码* @return*/private long getMachineNum(){long machinePiece;StringBuilder sb = new StringBuilder();Enumeration<NetworkInterface> e = null;try {e = NetworkInterface.getNetworkInterfaces();} catch (SocketException e1) {e1.printStackTrace();}while (e.hasMoreElements()) {NetworkInterface ni = e.nextElement();sb.append(ni.toString());}machinePiece = sb.toString().hashCode();return machinePiece;}
}

注意事项
这个雪花算法实现是一个常见的分布式唯一ID生成器,但它也有一些潜在的问题和优化空间:

  • 唯一性保证
    • 该算法的唯一性依赖于每个节点的机器ID(workerId)和数据中心ID(processId)。如果这些ID在不同节点上配置不正确,可能导致ID冲突。
    • 唯一性还依赖于时钟同步。如果时钟回拨(Clock Drift)或不稳定,可能会导致生成的ID不唯一。
  • 时钟回拨问题:
    • 该算法没有显式处理时钟回拨情况。如果系统时钟发生回拨,可能会导致生成的ID不连续,甚至出现重复。
    • 优化:您可以考虑在时钟回拨检测到时采取适当的措施,例如等待或重新生成ID。
  • 长期运行问题
    • 如果您的应用长期运行,可能会达到每毫秒生成的ID数量的限制,尤其是在高并发情况下。
    • 优化:可以根据实际需求调整位数,以提高每毫秒生成ID的上限。
  • 可扩展性问题
    • 该算法中的位数分配不一定适用于所有应用。如果您的应用需要更多的数据中心或机器节点,需要重新分配位数。
    • 优化:可以根据需求增加位数分配的灵活性,以支持更多的数据中心或机器。
  • 不适用于移动设备:
    • 该算法依赖于机器ID和数据中心ID的配置,对于移动设备等无法确定唯一ID的环境不适用。
    • 优化:可以考虑在这种情况下使用其他唯一ID生成策略。
  • 异常处理
    • 该算法在出现异常情况时没有提供良好的处理机制,例如时钟回拨异常。
    • 优化:添加适当的异常处理,以确保生成的ID在异常情况下也是正确的。
  • 总的来说,这个雪花算法实现在大多数情况下都能正常工作,但在特定情况下可能会出现问题。
  • 优化的策略会根据应用的具体需求而变化,可以根据需要进行调整,以确保生成的ID满足唯一性、连续性和性能要求。
  • 如果您需要更高级的解决方案,还可以考虑使用分布式ID生成服务或其他专用工具。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/94962.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

英语——分享篇——每日100词——601-700

disastrous——adj.灾难性的&#xff0c;完全失败的——disast(e)r灾难(熟词)ous藕丝(拼音)——灾难性的地震后大家只能吃藕丝 disorder——n.骚乱&#xff0c;混乱&#xff1b;vt.使失调——dis的士(谐音)order命令(熟词)——的士司机命令我稳住那场骚乱 distract——vt.转移…

C++ - 布隆过滤器

前言 之前介绍了 位图&#xff0c;位图在判断某一个 数是否存在&#xff0c;或者在计算某个数是否出现 一次 或者 两次这些问题之上有着非常高效的实现复杂度&#xff0c;它的时间复杂度 可以达到 O&#xff08;1&#xff09;&#xff0c;因为都是逻辑判断和 &#xff0c;常数…

Web前端-Vue2+Vue3基础入门到实战项目-Day2(指令补充, computed计算属性, watch侦听器, 水果购物车)

Web前端-Vue2Vue3基础入门到实战项目-Day2 指令补充指令修饰符v-bind 对样式控制的增强控制class案例 - 京东秒杀tab导航高亮控制style案例 - 控制进度条 v-model 应用于其他表单元素 computed计算属性基本使用computed计算属性 vs methods方法计算属性完整写法案例 - 成绩 wat…

论文学习:RT-DETR

RT-DETR 摘要 DETR取得显著性能&#xff0c;但高成本计算使其无法发挥无NMS的优势&#xff0c;无法实际应用。本文分析了NMS对准确性和速度的负面影响&#xff0c;并建立端到端的速度基准。第一个实时端到端检测器&#xff0c;高效处理多尺度特征&#xff0c;并提出IoU-aware…

【云备份】

文章目录 [toc] 1 :peach:云备份的认识:peach:1.1 :apple:功能了解:apple:1.2 :apple:实现目标:apple:1.3 :apple:服务端程序负责功能:apple:1.4 :apple:服务端功能模块划分:apple:1.5 :apple:客户端程序负责功能:apple:1.6 :apple:客户端功能模块划分:apple: 2 :peach:环境搭建…

mac电脑任务管理器 Things3 for Mac中文

Things 3是一款效率软件&#xff0c;可以帮助用户规划一天行程、管理项目&#xff0c;并使使用者按部就班地朝目标迈进。以下是Things 3的主要特点和功能&#xff1a; 待办事项&#xff1a;以“待办事项”为基本组成部分&#xff0c;每一则待办事项都是迈向大成就的一小步。用…

scala入门

视频 scala学习配套视频 资料目录 网盘地址&#xff1a;https://pan.baidu.com/s/1vJzjHhaC1NCcAGry6SLIpg&pwd1706 文档资料下载 第一章Scala的相关概述 第二章变量 第三章运算符 第四章循环 第五章方法 第七章继承、抽象类、匿名类 第八章特质 第九章包、样例…

Redis-双写一致性

双写一致性 双写一致性解决方案延迟双删&#xff08;有脏数据的风险&#xff09;分布式锁&#xff08;强一致性&#xff0c;性能比较低&#xff09;异步通知&#xff08;保证数据的最终一致性&#xff0c;高并发情况下会出现短暂的不一致情况&#xff09; 双写一致性 当修改了数…

Docker镜像管理

Docker 基本管理 Docker 概述 Docker是一个开源的应用容器引擎&#xff0c;基于go语言开发并遵循了apache2.0协议开源。 Docker是在Linux容器里运行应用的开源工具&#xff0c;是一种轻量级的“虚拟机”。 Docker 的容器技术可以在一台主机上轻松为任何应用创建一个轻量级的、…

Go 语言内置类型全解析:从布尔到字符串的全维度探究

目录 一、布尔类型定义基础用法声明与初始化逻辑运算 进阶用法条件语句循环结构函数返回值 常见错误与陷阱 二、整数类型定义基础用法声明与初始化运算符位运算 进阶用法数据溢出类型转换类型推断 特殊整数类型runebyte 常见问题和陷阱 三、浮点数类型定义基础用法声明与初始化…

云原生边缘计算KubeEdge安装配置

1. K8S集群部署&#xff0c;可以参考如下博客 请安装k8s集群&#xff0c;centos安装k8s集群 请安装k8s集群&#xff0c;ubuntu安装k8s集群 2.安装kubEedge 2.1 编辑kube-proxy使用ipvs代理 kubectl edit configmaps kube-proxy -n kube-system #修改kube-proxy#大约在40多行…

通过BeanFactotyPostProcessor动态修改@FeignClient的path

最近项目有个需求&#xff0c;要在启动后&#xff0c;动态修改FeignClient的请求路径&#xff0c;网上找到的基本都是在FeignClient里使用${…}&#xff0c;通过配置文件来定义Feign的接口路径&#xff0c;这并不能满足我们的需求 由于某些特殊原因&#xff0c;我们的每个接口…

Spring bean定义Spring Bean 的作用域

Spring bean定义 目录 Spring bean定义 Spring配置元数据 Spring Bean 的作用域 singleton作用域&#xff1a; 原型作用域&#xff1a; 示例&#xff1a; 形成应用程序的骨干是由Spring IoC容器所管理的对象称为bean。bean被实例化&#xff0c;组装&#xff0c;并通过Sprin…

运行pytorch时出现version `CXXABI_1.3.9‘ not found

发现问题&#xff1a;运行bert预测代码时出现如下错误 /envs/py38/lib/python3.8/site-packages/transformers/utils/import_utils.py", line 1184, in _get_module RuntimeError: Failed to import transformers.onnx.config because of the following error (look up …

华为OD机试真题【不含 101 的数】

1、题目描述 【不含 101 的数】 【题目描述】 小明在学习二进制时&#xff0c;发现了一类不含 101的数&#xff0c;也就是&#xff1a; 将数字用二进制表示&#xff0c;不能出现 101 。 现在给定一个整数区间 [l,r] &#xff0c;请问这个区间包含了多少个不含 101 的数&#…

互联网金融理财知识点简单总结

互联网金融理财知识点总结 互联网金融理财是指通过互联网平台进行资产管理和投资的一种金融方式。它结合了金融、科技和互联网&#xff0c;为投资者提供了更多选择和便捷性。本文将介绍互联网金融理财的关键知识点&#xff0c;包括理财基础、投资产品、风险管理和未来趋势等方…

Spring 体系架构模块和三大核心组件介绍

Spring架构图 模块介绍 1. Spring Core&#xff08;核心容器&#xff09;&#xff1a;提供了IOC,DI,Bean配置装载创建的核心实现。 spring-core &#xff1a;IOC和DI的基本实现 spring-beans&#xff1a;BeanFactory和Bean的装配管理(BeanFactory) spring-context&#xff1…

Python数据攻略-高级文件操作与Json序列化

当我们谈论数据分析时,第一个想到的可能是CSV或Excel文件,这些都是我们平时最常接触的数据格式。然而,在实际工作中,数据来源可能更加多样,比如网页上的表格、SQL数据库,甚至各种API返回的Json数据。因此,本篇文章的目标是让你掌握如何使用Pandas进行更高级的文件操作。…

【计算机网络】HTTPS协议详解

文章目录 一、HTTPS协议 介绍 1、1 HTTP协议不安全的体现 1、2 什么是 HTTPS协议 二、加密的一些概念 2、1 怎么理解加密 2、2 为什么要加密 2、3 常见的加密方式 2、2、1 对称加密 2、2、2 非对称加密 三、HTTPS协议探究加密过程 3、1 只使用对称加密 3、2 只是用非对称加密 3…

css3实现页面元素抖动效果

html <div id"shake" class"shape">horizontal shake</div>js&#xff08;vue3&#xff09; function shake(elemId) {const elem document.getElementById(elemId)console.log(获取el, elem)if (elem) {elem.classList.add(shake)setTimeou…