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

Java--Spring项目生成雪花算法数字(Twitter SnowFlake)

文章目录

        • 前言
        • 步骤
        • 查看结果

前言
  • 分布式系统常需要全局唯一的数字作为id,且该id要求有序,twitter的SnowFlake解决了这种需求,生成了符合条件的这种数字,本文将提供一个接口获取雪花算法数字。以下为代码。
步骤
  1. SnowFlakeUtils 雪花算法工具类。

    @Slf4j
    public class SnowFlakeUtils {private static final RedisOperation REDIS_OPERATION = ApplicationContextHelper.getBean(RedisOperation.class);private static final String LOCAL_IP = getLocalIp();private static volatile SnowFlakeUtils instance;/*** 该任务开始时间,必须手动设置(差值的唯一性)* 建议在生产部署时选择某一日的0时0分0秒0毫秒的时间戳,方便计算*/private static final long START_TIME = 1588733692671L;/*** 各个位的位数,Timestamp为41L(无需定义)*/private static final long DATA_CENTER_ID_BITS = 5L;private static final long WORKER_ID_BITS = 1L;private static final long SEQUENCE_BITS = 16L;/*** 各位的最大值*/private static final long DATA_CENTER_ID_MAX = ~(-1 << DATA_CENTER_ID_BITS);private static final long WORKER_ID_MAX = ~(-1 << WORKER_ID_BITS);private static final long SEQUENCE_MAX = ~(-1 << SEQUENCE_BITS);/*** 各位应该向左移动位数*/private static final long TIMESTAMP_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS + DATA_CENTER_ID_BITS;private static final long DATA_CENTER_ID_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS;private static final long WORKER_ID_SHIFT = SEQUENCE_BITS;/*** 数据中心ID*/private final long dataCenterId;private static final String DATA_CENTER_ID = "DATACENTERID";/*** 工作线程ID*/private final long workerId;private static final String WORKER_ID = "WORKERID";/*** 序列号*/private long sequence = 0L;/*** 上次时间(保证不回退)*/private long lastTimestamp = -1L;/**** 是否在高并发下*/private boolean isClock = false;public static SnowFlakeUtils getInstance() {if (instance == null) {synchronized (SnowFlakeUtils.class) {if (instance == null) {int dataCenterId = 0;int workerId = 0;while (true) {// tryCatch保证即使redis等出现问题也可以保证当前线程阻塞,重启redis即可处理继续处理try {String replace = RedisKeyConstant.SNOW_FLAKE_KEY.replace(DATA_CENTER_ID, String.valueOf(dataCenterId)).replace(WORKER_ID, String.valueOf(workerId));if (REDIS_OPERATION.setnx(replace, LOCAL_IP, 1, TimeUnit.MINUTES)) {instance = new SnowFlakeUtils(dataCenterId, workerId);break;}// 进行重新set直至成功,目前只运用dataCenterIdif (dataCenterId++ == DATA_CENTER_ID_MAX) {log.error("SnowFlake is getting CacheLock, please checkDATACENTERID_MAX={}", DATA_CENTER_ID_MAX);dataCenterId = 0;}} catch (Exception e) {log.error("SnowFlakeUtils get CacheLock Error, errorMsg:", e);try {Thread.sleep(MagicNum.THOUSAND);} catch (InterruptedException ex) {log.error(ex.getMessage(), ex);}}}}}}return instance;}public SnowFlakeUtils(long dataCenterId, long workerId) {if (dataCenterId > DATA_CENTER_ID_MAX || dataCenterId < 0) {throw new IllegalArgumentException(String.format("data center id can't be greater than %d or less than 0", DATA_CENTER_ID_MAX));}if (workerId > WORKER_ID_MAX || workerId < 0) {throw new IllegalArgumentException(String.format("worker id can't be greater than %d or less than 0", WORKER_ID_MAX));}this.dataCenterId = dataCenterId;this.workerId = workerId;String key = RedisKeyConstant.SNOW_FLAKE_KEY.replace(DATA_CENTER_ID, String.valueOf(dataCenterId)).replace(WORKER_ID, String.valueOf(workerId));log.info("SnowFlakeUtils Cache Key={}", key);// 起线程保证workerId和dataCenter组合不重复Thread thread = new Thread(new Runnable() {@Overridepublic void run() {while (true) {try {log.debug("SnowFlakeUtils is keep geting CacheLock-{}", key);String localIp = REDIS_OPERATION.get(key);if (LOCAL_IP.equals(localIp)) {REDIS_OPERATION.setex(key, LOCAL_IP, 1, TimeUnit.MINUTES);} else if (!REDIS_OPERATION.setnx(key, LOCAL_IP, 1, TimeUnit.MINUTES)) {throw new ProcessException(CommonConstants.ENUM_PROCESSING_EXCEPTION,"SnowFlakeUtils losed CacheLock-" + key + "." +"CacheLockKeeperThread broken!" +"Reday to retrieve CacheLock and Single Instance!");}Thread.sleep(MagicNum.FIFTY * MagicNum.THOUSAND);} catch (Exception e) {// 发生异常 将单例清除 并退出循环结束子线程synchronized (SnowFlakeUtils.class) {instance = null;}log.error(e.getMessage(),e);break;}}}});thread.setName("SnowFlake-CacheLockKeeper-" + dataCenterId + "-" + workerId);thread.start();}public void setClock(boolean clock) {this.isClock = clock;}public synchronized long nextId() {long timestamp = this.getTime();if (timestamp < lastTimestamp) {long offset = lastTimestamp - timestamp;if (offset <= MagicNum.FIVE) {try {this.wait(offset << 1);timestamp = this.getTime();if (timestamp < lastTimestamp) {throw new RuntimeException(String.format("Clock moved backwards, Refusing to generate id for %d milliseconds", offset));}} catch (InterruptedException e) {log.error(e.getMessage(), e);}} else {throw new RuntimeException(String.format("Clock moved backwards, Refusing to generate id for %d milliseconds", offset));}}if (lastTimestamp == timestamp) {sequence = sequence + 1;if (sequence > SEQUENCE_MAX) {timestamp = tilNextMillis(timestamp);sequence = 0;}} else {sequence = 0;}lastTimestamp = timestamp;return ((timestamp - START_TIME) << TIMESTAMP_SHIFT) |(dataCenterId << DATA_CENTER_ID_SHIFT) |(workerId << WORKER_ID_SHIFT) |sequence;}/*** 该毫秒达到上限,等待到下1毫秒*/private long tilNextMillis(long timestamp) {while (getTime() <= timestamp) {log.debug("单毫秒主键生成达到上限");}return this.getTime();}private long getTime() {if (isClock) {return SystemClock.currentTimeMillis();} else {return System.currentTimeMillis();}}private static String getLocalIp() {String ip = "";try {InetAddress addr = InetAddress.getLocalHost();ip += addr.getHostAddress();} catch (Exception e) {ip += "127.0.0.1";}ip += "_" + System.currentTimeMillis() + "_" + Math.random();log.info("SnowFlakeUtils Cache Value={}", ip);return ip;}
    }
    
  2. SystemClock工具类。

    /*** 由于高并发,在同一毫秒中会多次获取currentTimeMillis,而每次使用System.currentTimeMillis都会占用CPU(native方法).* 于是自定义类(single)来获取currentTimeMillis,实现方法是在此类中定义时间并设置一个周期任务(定时线程)1毫秒更新类中的时间*/
    public final class SystemClock {private static final SystemClock INSTANCE = new SystemClock(1);public static SystemClock getInstance() {return INSTANCE;}/*** 更新时间的时间间隔,默认为1毫秒*/private final long period;/*** 当前时间*/private final AtomicLong now;private SystemClock(long period) {this.period = period;this.now = new AtomicLong(System.currentTimeMillis());scheduleClockUpdate();}/*** 定时任务(设置为守护线程,1毫秒后开始更新)* scheduleAtFixedRate: 每次开始间隔为1毫秒* scheduleWithFixedDelay: 每次结束与开始为1毫秒*/private void scheduleClockUpdate() {ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {@Overridepublic Thread newThread(Runnable r) {Thread thread = new Thread(r, "System Clock");thread.setDaemon(true);return thread;}});executorService.scheduleAtFixedRate(new Runnable() {@Overridepublic void run() {now.set(System.currentTimeMillis());}}, period, period, TimeUnit.MILLISECONDS);}public static long currentTimeMillis() {return getInstance().now.get();}
    }
    
  3. ApplicationContextHelper Spring上下文工具类。

    @Slf4j
    @Component
    public class ApplicationContextHelper implements ApplicationContextAware {
    /**
    * Spring上下文
    */
    private static ApplicationContext applicationContext;/*** @return ApplicationContext*/public static ApplicationContext getApplicationContext() {return applicationContext;}/*** 获取ApplicationContextAware**/@Overridepublic void setApplicationContext(ApplicationContext applicationContext) {ApplicationContextHelper.applicationContext = applicationContext;}/*** 根据Class获取对应实例**/public static <T> T getBean(Class<T> clz) {return applicationContext.getBean(clz);}/*** 根据beanName获取对应实例*/public static <T> T getBean(String name, Class<T> requiredType) {return applicationContext.getBean(name, requiredType);}public static Object getBean(String name) {return applicationContext.getBean(name);}
    }
    
  4. RedisOperation获取 RedisOperation,Redis操作工具类。

  5. 在Controller里编写接口,测试结果。

    @RestController
    @RequestMapping("/part/util")
    public class UtilController {@ApiOperation("获取雪花数字")@GetMapping("/getSnowFlakeNo")public Result getSnowFlakeNo() {return Result.ok().data(String.valueOf(SnowFlakeUtils.getInstance().nextId()));}
    }
    
查看结果
  • 启动项目,有postman访问接口,查看结果如下,返回结果中data的值即为雪花算法数字。
    在这里插入图片描述

相关文章:

Java--Spring项目生成雪花算法数字(Twitter SnowFlake)

文章目录 前言步骤查看结果 前言 分布式系统常需要全局唯一的数字作为id&#xff0c;且该id要求有序&#xff0c;twitter的SnowFlake解决了这种需求&#xff0c;生成了符合条件的这种数字&#xff0c;本文将提供一个接口获取雪花算法数字。以下为代码。 步骤 SnowFlakeUtils …...

紫光展锐M6780丨画质增强——更炫的视觉体验

智能显示被认为是推动数字化转型和创新的重要技术之一。研究机构数据显示&#xff0c;预计到2035年底&#xff0c;全球智能显示市场规模将达到1368.6亿美元&#xff0c;2023-2035年符合年增长率为36.4%。 随着消费者对高品质视觉体验的需求不断增加&#xff0c;智能手机、平板…...

控制el-table的列显示隐藏

控制el-table的列显示隐藏&#xff0c;一般的话可以通过循环来实现&#xff0c;但是假如业务及页面比较复杂的话&#xff0c;list数组循环并不好用。 在我们的页面中el-table-column是固定的&#xff0c;因为现在是对现有的进行维护和迭代更新。 对需要控制列显示隐藏的页面进…...

2024上海国际冶金及材料分析测试仪器设备展览会

2024上海国际冶金及材料分析测试仪器设备展览会 时间&#xff1a;2024年12月18&#xff5e;20日 地点&#xff1a;上海新国际博览中心 ◆ 》》》组织机构&#xff1a; 主办单位&#xff1a;全联冶金商会、中国宝武钢铁集团有限公司、上海市金属学会 支持单位&#xff…...

商业定位,1元平价商业咨询:豪威尔咨询!平价咨询。

在做生意之前&#xff0c;就需要对企业整体进行一完整的商业定位&#xff0c;才能让商业定位带动企业进行飞速发展。 所以&#xff0c;包含商业定位的有效工作内容就显得极为重要&#xff0c;今天&#xff0c;小编特地为大家整理出了商业定位所需要的筹备的工作&#xff0c;如下…...

2. Presto应用

该笔记来源于网络&#xff0c;仅用于搜索学习&#xff0c;不保证所有内容正确。文章目录 1、Presto安装使用2、事件分析3、漏斗分析4、漏斗分析UDAF开发开发UDF插件开发UDAF插件 5、漏斗测试 1、Presto安装使用 参考官方文档&#xff1a;https://prestodb.io/docs/current/ P…...

工业级安卓PDA超高频读写器手持掌上电脑,RFID电子标签读写器

掌上电脑&#xff0c;又称为PDA。工业级PDA的特点就是坚固&#xff0c;耐用&#xff0c;可以用在很多环境比较恶劣的地方。 随着技术的不断发展&#xff0c;加快了数字化发展趋势&#xff0c;RFID技术就是RFID射频识别及技术&#xff0c;作为一种新兴的非接触式的自动识别技术&…...

Prompt提示工程上手指南:基础原理及实践(一)

想象一下&#xff0c;你在装饰房间。你可以选择一套标准的家具&#xff0c;这是快捷且方便的方式&#xff0c;但可能无法完全符合你的个人风格或需求。另一方面&#xff0c;你也可以选择定制家具&#xff0c;选择特定的颜色、材料和设计&#xff0c;以确保每件家具都符合你的喜…...

Redis如何保证缓存和数据库一致性?

背景 现在我们在面向增删改查开发时&#xff0c;数据库数据量大时或者对响应要求较快&#xff0c;我们就需要用到Redis来拿取数据。 Redis&#xff1a;是一种高性能的内存数据库&#xff0c;它将数据以键值对的形式存储在内存中&#xff0c;具有读写速度快、支持多种数据类型…...

学完C/C++,再学Python是一种什么体验?

你好&#xff0c;我是安然无虞。 文章目录 变量及类型变量类型动态类型特性 注释输入输出通过控制台输出通过控制台输入 运算符算术运算符关系运算符逻辑运算符赋值运算符 条件循环语句条件语句语法格式代码案例缩进和代码块空语句pass 循环语句while循环语法格式代码案例 for…...

ssm基于Java的壁纸网站设计与实现论文

目 录 目 录 I 摘 要 III ABSTRACT IV 1 绪论 1 1.1 课题背景 1 1.2 研究现状 1 1.3 研究内容 2 2 系统开发环境 3 2.1 vue技术 3 2.2 JAVA技术 3 2.3 MYSQL数据库 3 2.4 B/S结构 4 2.5 SSM框架技术 4 3 系统分析 5 3.1 可行性分析 5 3.1.1 技术可行性 5 3.1.2 操作可行性 5 3…...

零基础也可以探索 PyTorch 中的上采样与下采样技术

目录 torch.nn子模块Vision Layers详解 nn.PixelShuffle 用法与用途 使用技巧 注意事项 参数 示例代码 nn.PixelUnshuffle 用法与用途 使用技巧 注意事项 参数 示例代码 nn.Upsample 用法与用途 使用技巧 注意事项 参数 示例代码 nn.UpsamplingNearest2d …...

代码随想录算法训练营Day23|669. 修剪二叉搜索树、108.将有序数组转换为二叉搜索树、538.把二叉搜索树转换为累加树

目录 669. 修剪二叉搜索树 前言 思路 递归法 108.将有序数组转换为二叉搜索树 前言 递归法 538.把二叉搜索树转换为累加树 前言 递归法 总结 669. 修剪二叉搜索树 题目链接 文章链接 前言 本题承接昨天二叉搜索树的插入和删除操作题目&#xff0c;要对整棵二叉搜索树…...

乱 弹 篇(一)

题记 对于“乱弹”这个词汇的释义&#xff0c;《辞海》上仅有“ 戏曲剧种&#xff0c;亦指声腔 ”8个字。而由于“乱弹 ”的“ 弹”谐音谈”&#xff0c;这就容易让人联想到“乱谈”。不过从文体上看&#xff0c;“乱谈”也非乱七八糟之谈&#xff0c;反倒是“东西南北&#x…...

《JVM由浅入深学习【八】 2024-01-12》JVM由简入深学习提升分(JVM的垃圾回收算法)

目录 JVM的垃圾回收算法1. 标记-清除算法&#xff08;Mark-Sweep&#xff09;原理步骤优点缺点 2. 复制算法&#xff08;Copying&#xff09;原理步骤优点缺点 3. 标记-整理算法&#xff08;Mark-Compact&#xff09;原理步骤优点缺点 4. 分代收集算法&#xff08;Generational…...

在矩阵回溯中进行累加和比较的注意点

1 总结 在回溯时&#xff0c;如果递归函数采用void返回&#xff0c;在入口处使用了sum变量&#xff0c;那么一般在初次调用dfs的地方&#xff0c;这个sum的初始值可能不是0,而是数组的对应指针的值&#xff0c;在比较操作的时候&#xff0c;需要在for循环开始之前进行&#xf…...

AI语音机器人的发展

第一代AI语音机器人具体投入研发的开始时间不太清楚&#xff0c;只记得2017年的下半年就已经开始接触到成型的AI语音机器人&#xff0c;并且正式商用。语音识别效果还不多&#xff0c;大多都是接入的科大讯飞或者百度的ASR。 2018年算是AI语音机器人的“青春期”吧&#xff0c;…...

SQL语句错误this is incompatible with sql_mode=only_full_group_by解决方法

一、原理层面 这个错误发生在mysql 5.7.5 版本及以上版本会出现的问题&#xff1a; mysql 5.7.5版本以上默认的sql配置是:sql_mode“ONLY_FULL_GROUP_BY”&#xff0c;这个配置严格执行了"SQL92标准"。 很多从5.6升级到5.7时&#xff0c;为了语法兼容&#xff0c;大部…...

静态长效代理IP和动态短效代理IP有哪些用途?分别适用场景是什么?

静态长效代理IP和动态短效代理IP是两种常见的代理IP类型&#xff0c;它们在用途和适用场景上存在一定的差异。了解它们的特性以及使用场景有助于我们更好地利用代理IP&#xff0c;提高网络访问的效率和安全性。 一、静态长效代理IP 1. 用途 静态长效代理IP是指长期保持稳定的代…...

基于Spring Boot+Vue的课堂管理系统(前后端分离)

该项目完全免费 介绍 基于Spring BootVue的课堂管理系统。前后端分离。包含教师授课管理、学生选退课、聊天室、签到、笔记管理模块等。 技术架构 SpringBoot MyBatis Redis WebSocket VueCLI Axios Element UI 项目特点&#xff1a; 1、后台使用MyBatis连接数据库&…...

ubuntu搭建nfs服务centos挂载访问

在Ubuntu上设置NFS服务器 在Ubuntu上&#xff0c;你可以使用apt包管理器来安装NFS服务器。打开终端并运行&#xff1a; sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享&#xff0c;例如/shared&#xff1a; sudo mkdir /shared sud…...

rknn优化教程(二)

文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK&#xff0c;开始写第二篇的内容了。这篇博客主要能写一下&#xff1a; 如何给一些三方库按照xmake方式进行封装&#xff0c;供调用如何按…...

循环冗余码校验CRC码 算法步骤+详细实例计算

通信过程&#xff1a;&#xff08;白话解释&#xff09; 我们将原始待发送的消息称为 M M M&#xff0c;依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)&#xff08;意思就是 G &#xff08; x ) G&#xff08;x) G&#xff08;x) 是已知的&#xff09;&#xff0…...

镜像里切换为普通用户

如果你登录远程虚拟机默认就是 root 用户&#xff0c;但你不希望用 root 权限运行 ns-3&#xff08;这是对的&#xff0c;ns3 工具会拒绝 root&#xff09;&#xff0c;你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案&#xff1a;创建非 roo…...

GC1808高性能24位立体声音频ADC芯片解析

1. 芯片概述 GC1808是一款24位立体声音频模数转换器&#xff08;ADC&#xff09;&#xff0c;支持8kHz~96kHz采样率&#xff0c;集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器&#xff0c;适用于高保真音频采集场景。 2. 核心特性 高精度&#xff1a;24位分辨率&#xff0c…...

Netty从入门到进阶(二)

二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架&#xff0c;用于…...

mac 安装homebrew (nvm 及git)

mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用&#xff1a; 方法一&#xff1a;使用 Homebrew 安装 Git&#xff08;推荐&#xff09; 步骤如下&#xff1a;打开终端&#xff08;Terminal.app&#xff09; 1.安装 Homebrew…...

WebRTC从入门到实践 - 零基础教程

WebRTC从入门到实践 - 零基础教程 目录 WebRTC简介 基础概念 工作原理 开发环境搭建 基础实践 三个实战案例 常见问题解答 1. WebRTC简介 1.1 什么是WebRTC&#xff1f; WebRTC&#xff08;Web Real-Time Communication&#xff09;是一个支持网页浏览器进行实时语音…...

零知开源——STM32F103RBT6驱动 ICM20948 九轴传感器及 vofa + 上位机可视化教程

STM32F1 本教程使用零知标准板&#xff08;STM32F103RBT6&#xff09;通过I2C驱动ICM20948九轴传感器&#xff0c;实现姿态解算&#xff0c;并通过串口将数据实时发送至VOFA上位机进行3D可视化。代码基于开源库修改优化&#xff0c;适合嵌入式及物联网开发者。在基础驱动上新增…...

HybridVLA——让单一LLM同时具备扩散和自回归动作预测能力:训练时既扩散也回归,但推理时则扩散

前言 如上一篇文章《dexcap升级版之DexWild》中的前言部分所说&#xff0c;在叠衣服的过程中&#xff0c;我会带着团队对比各种模型、方法、策略&#xff0c;毕竟针对各个场景始终寻找更优的解决方案&#xff0c;是我个人和我司「七月在线」的职责之一 且个人认为&#xff0c…...