生成12位短id,自增且不连续,永不重复,不依赖数据库
基本思路:
设计模式:单例模式
是否加锁:是 synchronized
获取最后一次生成的时间戳值T0
限定初始时间为2023-08-01 00:00:00,获取当前时间时间戳T1,T1与初始时间的毫秒差值T2,转为16进制,转为字符串为r1,获取该字符串的长度L1
获取L2 (length - L1) ,获取L2位数字的16进制自增数值范围,取最大值max
现数据库批量导入数据速度为 n条/ms
平均步长为max/n,(0~平均步长)的平均数为max/n/2,假设使用平均步长最为随机步长范围,最终的值与max相差较远,大约后一半的数字没有被使用
将平均步长*2-平均步长*容错因子(0.1)的值作为我们随机步长的范围 容错因子:减小溢出概率
随机步长step = max/n*2 - max/n*0.1
获取T1
如果T1 == T0,序列值seqNum = seqNum + step (转为16进制),若seqNum > max,该线程暂停1毫秒后刷新r1
如果T1 > T0,序列值seqNum = 0 + step
设置T0
代码实现如下:
/*** 生成短id* @author mayu*/
public class ShortIdWorker {/*** 初始时间限定为2023-08-01 00:00:00*/private final static long START_STAMP = 1690819200000L;/*** 容错因子*/private final static int FAULT_TOLERANCE_FACTOR = 10;/*** 默认长度*/private final static int DEFAULT_ID_LENGTH = 12;/*** 数据库每毫秒可保存的数据,结合列的数量取值,建议实测后更改*/private final static int DEFAULT_TRANSFER_SPEED_PER_MILLISECOND = 50;private final int length;private final int transferSpeedPerMillisecond;/*** 上次运行时间*/private long lastStamp = -1L;/*** 增长序列*/private int seqNum;private static ShortIdWorker instance;/*** 单例模式*/public static ShortIdWorker getInstance() {if (null == instance) {instance = new ShortIdWorker();}return instance;}public static ShortIdWorker newInstance(int length, int transferSpeedPerMillisecond) {return new ShortIdWorker(length, transferSpeedPerMillisecond);}/*** 默认使用12位id,数据库每毫秒新增数据为50条*/private ShortIdWorker() {this(DEFAULT_ID_LENGTH, DEFAULT_TRANSFER_SPEED_PER_MILLISECOND);}private ShortIdWorker(int length, int transferSpeedPerMillisecond) {this.length = length;this.transferSpeedPerMillisecond = transferSpeedPerMillisecond;}/*** @return 生成后的id* <p>* 例:757b12c001d3* 共length位id,前x位为时间戳差值的16进制,后y位为不固定步长的自增序列*/public synchronized String nextId() {long now = now();// 获取16进制时间戳前缀String stampPrefix = getStampStr(now);// 获取第二段增长序列的长度l2int l2 = this.length - stampPrefix.length();// 获取l2位16进制的最大值int max = IntStream.range(0, l2).map(i -> 16).reduce(1, (a, b) -> a * b) - 1;// 获取增长的平均步长averageStepLengthint averageStepLength = max / this.transferSpeedPerMillisecond;// 取步长范围// averageStepLength的平均值是averageStepLength/2,累加的情况下会有后一半的空间浪费问题,故取值为averageStepLength*2,平均值为averageStepLength// 取随机数的结果不可控,上行中列举的只是近似值,为防止多次溢出影响程序执行时间,再减去容错因子,减小溢出概率(容错因子建议在本地系统实测后更改)int randomStepLengthMax = (averageStepLength << 1) - (averageStepLength / FAULT_TOLERANCE_FACTOR);// 在步长范围内获取随机步长int randomStepLength = new Random().nextInt(randomStepLengthMax) + 1;// 当上次运行时间小于当前时间或第一次运行时,增长序列赋值为随机步长,设置最后运行时间if (this.lastStamp < now || this.lastStamp == -1L) {this.seqNum = randomStepLength;this.lastStamp = now;// 当上次运行时间与当前运行时间处于同一毫秒时} else if (this.lastStamp == now) {// 增长序列以随机步长为步长递增this.seqNum += randomStepLength;// 当增长序列大于最大值时if (this.seqNum > max) {// 程序暂停一毫秒LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(1));// 重新获取前缀,增长序列重新开始this.seqNum = randomStepLength;Long newNow = now();this.lastStamp = newNow;stampPrefix = getStampStr(newNow);}} else {// 时钟回拨,报错throw new IllegalStateException("Clock moved backwards. Reject to generate id");}// 将增长序列转为16进制与时间戳拼接return stampPrefix + String.format("%0" + l2 + "X", new BigInteger(String.valueOf(this.seqNum), 10));}private String hex10To16(String str) {return String.format("%X", new BigInteger(str, 10));}private long now() {return System.currentTimeMillis();}/*** 获取传入时间与开始时间的间隔毫秒数,将结果转为16进制* @param now 时间戳* @return*/private String getStampStr(Long now) {return hex10To16(String.valueOf(now - START_STAMP));}
8位16进制可使用到4201年-03-20 07:32:15,后续时间戳所占位数自动变为9位,id总长度不变,不用担心id用尽的问题。
代码中关于时间赋值的代码请谨慎改动,顺序颠倒会产生bug。
相关文章:
生成12位短id,自增且不连续,永不重复,不依赖数据库
基本思路: 设计模式:单例模式 是否加锁:是 synchronized 获取最后一次生成的时间戳值T0 限定初始时间为2023-08-01 00:00:00,获取当前时间时间戳T1,T1与初始时间的毫秒差值T2,转为16进制,转为字符串为r1,获取该字符串的长度L1…...
Zip压缩文件夹php打包函数代码
Zip压缩文件夹php打包函数代码,Zip相关函数是PHP的扩展功能,此函数可以直接复制使用。 以下是代码: <?php # 将文件夹的文件压缩到文件里 class Zip {/*** 将目标文件夹下的内容压缩到zip中(zip包含文件夹目录)* @param $sourcePath *文件夹路径 例: /home/test* @p…...
RISC-V交叉工具链riscv-gnu-toolchain编译
文章目录 1、下载2、编译1. 依赖安装2. 编译 3、运行 1、下载 $ sudo apt-get install git wget build-essential $ git clone https://github.com/riscv-collab/riscv-gnu-toolchain $ git checkout 2023.06.02注意上面 clone 的仓库,我们称其为构建脚本仓库&…...
我能“C“——指针进阶(上)
目录 指针的概念 1. 字符指针 2. 指针数组 3. 数组指针 3.1 数组指针的定义 3.2 &数组名VS数组名 3.3 数组指针的使用 4. 数组参数、指针参数 4.1 一维数组传参 4.2 二维数组传参 4.3 一级指针传参 4.4 二级指针传参 5. 函数指针 阅读两段有趣的代码&…...
SQLServer2008数据库还原失败 恢复失败
源地址:http://www.taodudu.cc/news/show-1609349.html?actiononClick 还原数据库问题解决方案 在还原数据库“Dsideal_school_db”时,有时会遇见上图中的问题“因为数据库正在使用,所以无法获得对数据库的独占访问权”,此时我们…...
【微服务部署】04-ForwardedHeaders
文章目录 1. ForwardedHeaders1.1 场景1.2 关键的HTTP头1.3 核心处理要点 1. ForwardedHeaders 1.1 场景 获取用户IP获取用户请求的原始URL 1.2 关键的HTTP头 X-Forwarded-ForX-Forwarded-ProtoX-Forwarded-Host 1.3 核心处理要点 设置PathBase设置ForwardedHeaders中间件…...
JVM 垃圾收集器
重点:CMS,G1,ZGC 主要垃圾收集器如下,图中标出了它们的工作区域、垃圾收集算法,以及配合关系。 Serial 收集器 Serial 收集器是最基础、历史最悠久的收集器。 如同它的名字(串行),…...
CSS 样式使用link和@import有什么区别
在页面导入样式时,使用link和import有以下区别: 位置:link标签可以放置在HTML文档的head或body中的任何位置,而import规则必须出现在CSS样式表的顶部。 加载方式:当浏览器解析到link标签时,会立即请求并加…...
LeetCode-2511-最多可以摧毁的敌人城堡数目
题目链接 代码实现: class Solution {/** 找 1 -> -1 的时候,经过0的最大个数* 解题思路:双指针*/public int captureForts(int[] forts) {int len forts.length;if(len1){return 0;}int max Integer.MIN_VALUE;boolean flag false;boo…...
iOS开发Swift-2-图片视图、App图标-赏月App
1.创建新项目 点击File - New - Project。 选择Single View App,点击Next。 填写文件信息,点击Next。 选择文件位置,点击Create。 修改App显示名称为 “赏月”。 2.设置背景色 选择Main,点击View界面,选择右边属性&…...
node18 vue2启动报错 error:0308010C:digital envelope routines::unsupported
出现原因 貌似是因为是因为 node 17版本开始发布的OpenSSL3.0, 而OpenSSL3.0对允许算法和密钥大小增加了严格的限制,可能会对生态系统造成一些影响。 解决方法 第一种方法降低node版本 降低到17以下即可 ,如项目不能降低版本 看后面的解决方式 第二…...
Java8实战-总结18
Java8实战-总结18 使用流筛选和切片用谓词筛选筛选各异的元素截短流跳过元素 使用流 流让你从外部迭代转向内部迭代。这样,就用不着写下面这样的代码来显式地管理数据集合的迭代(外部迭代)了: List<Dish> vegetarianDishes new ArrayList<>…...
ARM编程模型-指令流水线
流水线技术通过多个功能部件并行工作来缩短程序执行时间,提高处理器核的效率和吞吐率,从而成为微处理器设计中最为重要的技术之一。 1. 3级流水线 到ARM7为止的ARM处理器使用简单的3级流水线,它包括下列流水线级。 (1࿰…...
邮件营销:高效的节日宣传方式
每个国家都有当地的传统节日,像是我国刚过去的端午节,即将迎来的中秋节、国庆节。我们除了会进行一些传统习俗外,各路商家还会趁这个机会开启促销活动。 对于公司来讲,抓住每一次营销活动都可能会带来更高的营销额,或…...
Leetcode109. 有序链表转换二叉搜索树
力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台 给定一个单链表的头节点 head ,其中的元素 按升序排序 ,将其转换为高度平衡的二叉搜索树。 本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度…...
基于Googlenet深度学习网络的人脸身份识别matlab仿真
目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 ..................................................................... % 定义修改的范围 …...
vue2 生命周期,工程化开发入门
一、今日目标 1.生命周期 生命周期介绍生命周期的四个阶段生命周期钩子声明周期案例 2.工程化开发入门 工程化开发和脚手架项目运行流程组件化组件注册 二、Vue生命周期 思考:什么时候可以发送初始化渲染请求?(越早越好)什么…...
Elasticsearch 分布式搜索——聚合
1.聚合的种类 聚合常见的有三类: **桶(Bucket)**聚合:用来对文档做分组 TermAggregation:按照文档字段值分组,例如按照品牌值分组、按照国家分组Date Histogram:按照日期阶梯分组,例…...
苹果将在iPhone16系列中引入微透镜阵列技术,亮度更高、功耗更低
根据韩国媒体The Elec的报道,苹果公司正与其主要供应商三星和LG展开合作,以评估并衡量是否有必要在明年的iPhone 16系列中引入微透镜(micro-lens)技术来升级屏幕。 这项方案集中在OLED屏幕架构上,计划采用微透镜阵列&…...
Window10 安装 Lua
1、下载地址:https://luabinaries.sourceforge.net/download.html 2、下载 3、解压后共有4个文件,这里我把这几个文件放到如下目录 D:\Program Files\lua-5.4.2\bin 4、定义环境变量 5、打开 powershell,运行 lua54 -v PS C:\Windows\syste…...
网络六边形受到攻击
大家读完觉得有帮助记得关注和点赞!!! 抽象 现代智能交通系统 (ITS) 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 (…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...
树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法
树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作,无需更改相机配置。但是,一…...
ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放
简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…...
vue3 定时器-定义全局方法 vue+ts
1.创建ts文件 路径:src/utils/timer.ts 完整代码: import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...
Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!
一、引言 在数据驱动的背景下,知识图谱凭借其高效的信息组织能力,正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合,探讨知识图谱开发的实现细节,帮助读者掌握该技术栈在实际项目中的落地方法。 …...
【python异步多线程】异步多线程爬虫代码示例
claude生成的python多线程、异步代码示例,模拟20个网页的爬取,每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程:允许程序同时执行多个任务,提高IO密集型任务(如网络请求)的效率…...
深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用
文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么?1.1.2 感知机的工作原理 1.2 感知机的简单应用:基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...
【JVM面试篇】高频八股汇总——类加载和类加载器
目录 1. 讲一下类加载过程? 2. Java创建对象的过程? 3. 对象的生命周期? 4. 类加载器有哪些? 5. 双亲委派模型的作用(好处)? 6. 讲一下类的加载和双亲委派原则? 7. 双亲委派模…...
wpf在image控件上快速显示内存图像
wpf在image控件上快速显示内存图像https://www.cnblogs.com/haodafeng/p/10431387.html 如果你在寻找能够快速在image控件刷新大图像(比如分辨率3000*3000的图像)的办法,尤其是想把内存中的裸数据(只有图像的数据,不包…...
