当前位置: 首页 > news >正文

Java 雪花算法:分布式唯一ID生成的魔法秘籍

欢迎来到本次博客的旅程,今天我们要揭开一个神秘算法的面纱,它就是在分布式系统中广受欢迎的——雪花算法(Snowflake)。这个算法不是用来预测雪花的形状,而是用来生成唯一的ID,保证在分布式系统中,每一个ID都是独一无二的。接下来,我将带领大家一步一步深入了解这个神奇的算法,并教你如何在Java中实现它。准备好了吗?让我们开始吧!

一、什么是雪花算法?

雪花算法由Twitter在2010年发布,用于生成分布式系统中的唯一ID。想象一下,你有一大片雪花,每一片都独一无二,这就是雪花算法的工作原理。它生成的ID不仅唯一,还按时间有序。

雪花算法生成的ID是一个64位的整数,这个整数由以下几部分组成:

  • 1位的符号位,总是0,表示正数。
  • 41位的时间戳,精确到毫秒,可以使用约69年。
  • 10位的机器ID,表示最多支持1024个节点。
  • 12位的序列号,每毫秒可以生成4096个不同的ID。

这样组合在一起,就形成了一个唯一的ID。

二、为什么要用雪花算法?

在分布式系统中,生成唯一的ID是一个常见问题。常见的方法有UUID和数据库自增ID,但它们都有各自的缺点:

  • UUID:虽然唯一,但长度较长,不利于存储和索引。
  • 数据库自增ID:需要依赖数据库,不利于分布式扩展。

相比之下,雪花算法生成的ID短小精悍,按时间有序,非常适合在分布式系统中使用。

三、雪花算法的工作原理

让我们通过一个示例,详细了解雪花算法是如何工作的。

假设我们在2024年1月1日开始使用雪花算法生成ID,机器ID为1,每毫秒生成的序列号从0开始。

  1. 获取当前时间戳:获取当前时间戳(以毫秒为单位),减去一个固定的时间起点(例如2024年1月1日的时间戳),得到时间差。
  2. 拼接机器ID和序列号:将机器ID和序列号拼接在时间戳之后,形成一个64位的ID。

举个例子,如果当前时间戳是1000毫秒,机器ID是1,序列号是0,那么生成的ID就是:

ID = 时间戳 << 22 | 机器ID << 12 | 序列号= 1000 << 22 | 1 << 12 | 0= 4194304000
四、Java实现雪花算法

接下来,我们在Java中实现雪花算法。这个实现包含了基本的ID生成逻辑,以及一些必要的同步控制,确保在高并发环境下的正确性。

public class SnowflakeIdGenerator {// 起始时间戳private final long twepoch = 1577836800000L; // 2020-01-01// 机器ID所占的位数private final long workerIdBits = 5L;// 数据中心ID所占的位数private final long datacenterIdBits = 5L;// 支持的最大机器IDprivate final long maxWorkerId = -1L ^ (-1L << workerIdBits);// 支持的最大数据中心IDprivate final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);// 序列在ID中占的位数private final long sequenceBits = 12L;// 机器ID向左移12位private final long workerIdShift = sequenceBits;// 数据中心ID向左移17位private final long datacenterIdShift = sequenceBits + workerIdBits;// 时间戳向左移22位private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;// 生成序列的掩码,这里为4095private final long sequenceMask = -1L ^ (-1L << sequenceBits);private long workerId; // 机器IDprivate long datacenterId; // 数据中心IDprivate long sequence = 0L; // 序列号private long lastTimestamp = -1L; // 上次生成ID的时间戳// 构造函数public SnowflakeIdGenerator(long workerId, long datacenterId) {if (workerId > maxWorkerId || workerId < 0) {throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));}if (datacenterId > maxDatacenterId || datacenterId < 0) {throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));}this.workerId = workerId;this.datacenterId = datacenterId;}// 生成IDpublic synchronized long nextId() {long timestamp = timeGen();if (timestamp < lastTimestamp) {throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));}if (lastTimestamp == timestamp) {sequence = (sequence + 1) & sequenceMask;if (sequence == 0) {timestamp = tilNextMillis(lastTimestamp);}} else {sequence = 0L;}lastTimestamp = timestamp;return ((timestamp - twepoch) << timestampLeftShift) |(datacenterId << datacenterIdShift) |(workerId << workerIdShift) |sequence;}// 阻塞到下一个毫秒,直到获得新的时间戳protected long tilNextMillis(long lastTimestamp) {long timestamp = timeGen();while (timestamp <= lastTimestamp) {timestamp = timeGen();}return timestamp;}// 返回当前时间,以毫秒为单位protected long timeGen() {return System.currentTimeMillis();}
}

以上代码中,SnowflakeIdGenerator 类实现了雪花算法的核心逻辑。让我们来逐步解释每一个部分。

  • 变量定义:定义了机器ID、数据中心ID、序列号以及时间戳等变量。
  • 构造函数:初始化机器ID和数据中心ID,并进行合法性检查。
  • nextId 方法:生成唯一ID,使用同步关键字保证线程安全。
  • tilNextMillis 方法:阻塞直到下一毫秒,以防止生成重复ID。
  • timeGen 方法:获取当前时间戳。
五、使用示例

现在,我们可以创建 SnowflakeIdGenerator 的实例,并生成唯一ID了。

public class Main {public static void main(String[] args) {SnowflakeIdGenerator idGenerator = new SnowflakeIdGenerator(1, 1);for (int i = 0; i < 10; i++) {long id = idGenerator.nextId();System.out.println("Generated ID: " + id);}}
}

以上代码将生成10个唯一ID,并打印到控制台。

六、结论

雪花算法在分布式系统中生成唯一ID方面表现卓越。通过详细的解释和Java实现,希望你已经掌握了这个强大的工具。无论你是在开发大型分布式系统,还是需要生成唯一ID,雪花算法都是一个值得信赖的选择。

希望这篇博客不仅帮助你理解了雪花算法,还能让你在实现过程中获得乐趣。如果你有任何问题或建议,欢迎在评论区留言,我们一起探讨!

祝编码愉快!

http://www.lryc.cn/news/361363.html

相关文章:

  • mybatis配置环境流程
  • UE5增强输入系统入门
  • Python 语法好乱:深度解析与应对策略
  • 移动端框架:加速移动应用开发与提升跨平台兼容性
  • Linux systemctl:掌握软件启动和关闭的利器
  • Jmeter干货分享:当你的Log viewer不显示日志时,可能是引入的Jar包冲突导致
  • 网络编程TCP
  • C++中的迭代器
  • 8.1 Go 包的概念与使用
  • 第一篇【传奇开心果系列】AI工业应用经典算法和Python示例:基于AI的智能制造技术经典算法与Python实践
  • Mathtype插入编号的高级格式会重置之前的简单格式的问题
  • 弘君资本:存储芯片概念强势,西测测试三连板,佰维存储涨超10%
  • 【机器学习】逻辑回归:原理、应用与实践
  • C++:list模拟实现
  • 植物大战僵尸杂交版全平台 PC MAC 安卓手机下载安装详细图文教程
  • 发送Http请求的两种方式
  • 【算法训练记录——Day23】
  • 【wiki知识库】04.SpringBoot后端实现电子书的增删改查以及前端界面的展示
  • NTLM Relay Gat:自动化NTLM中继安全检测工具
  • 摸鱼大数据——Hive函数14
  • elasticsearch的常规操作--增删改查和批量处理
  • 盘点2024年还在活跃发版的开源私有网盘项目附源码链接
  • MySQL 使用方法以及教程
  • 算法学习笔记——二进制
  • 计算机网络介绍
  • 解锁数据宝藏:高效查找算法揭秘
  • 利用EasyCVR视频智能监控技术,构建智慧化考场监管体系
  • 深度解析:速卖通618风控下自养号测评的技术要点
  • 国产算力——沐曦GPU性能及应用
  • 贪心算法拓展(反悔贪心)