java id值_Java实现数值型ID生成器
基于Twitter ID 生成策略
每秒能生成几十万条 ID
ID 生成要以一种非协作的(uncoordinated)的方式进行,例如不能利用一个全局的原子变量。
ID 大致有序,就是说生成时间相近的两个ID,它们的值也应当相近
按 ID 排序后满足 k-sorted 条件。如果序列 A 要满足 k-sorted,当且仅当对于任意的 p, q,如果 1 <= p <= q - k (1 <= p <= q <= n),则有 A[p] <= A[q]。换句话说,如果元素 p 排在 q 前面,且相差至少 k 个位置,那么 p 必然小于或等于 q。如果ID序列满足这个条件,要获取第 r 条ID之后的记录,只要从第 r - k 条开始查找即可。
解决方案
Twitter 解决这两个问题的方案非常简单高效:每一个 ID 都是 64 位数字,由时间戳、节点号和序列编号组成。其中序列编号是每个节点本地生成的序号,而节点号则由 ZooKeeper 维护。
实现代码
/**
* @author zhujuan
* From: https://github.com/twitter/snowflake
* An object that generates IDs.
* This is broken into a separate class in case
* we ever want to support multiple worker threads
* per process
*/
public class IdWorker {
protected static final Logger LOG = LoggerFactory.getLogger(IdWorker.class);
private long workerId;
private long datacenterId;
private long sequence = 0L;
private long workerIdBits = 5L;
private long datacenterIdBits = 5L;
private long maxWorkerId = -1L ^ (-1L << workerIdBits);
private long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
private long sequenceBits = 12L;
private long workerIdShift = sequenceBits;
private long datacenterIdShift = sequenceBits + workerIdBits;
private long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
private long sequenceMask = -1L ^ (-1L << sequenceBits);
private long lastTimestamp = -1L;
public IdWorker(long workerId, long datacenterId) {
// sanity check for workerId
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;
LOG.info(String.format("worker starting. timestamp left shift %d, datacenter id bits %d, worker id bits %d, sequence bits %d, workerid %d", timestampLeftShift, datacenterIdBits, workerIdBits, sequenceBits, workerId));
}
public synchronized long nextId() {
long timestamp = timeGen();
if (timestamp < lastTimestamp) {
LOG.error(String.format("clock is moving backwards. Rejecting requests until %d.", 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 << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | sequence;
}
}
基于Instagram 的ID生成策略
生成的ID可以按时间排序
与Twitter需求大致相同
ID最好是64bit的
为了索引更小且方便存储在像Redis这样的系统中
按照某种用户标识进行逻辑分片
解决方案
41bits 存储毫秒格式的时间
10bits 表示逻辑分片ID
原方案是13bits(最多8192个逻辑分片),这里为了与基于Twitter的策略保持大致一致,改成了10bits
12bits 存储自增序列值
原方案是10bits(最多1024个序列),这里为了与基于Twitter的策略保持大致一致,改成了12bits(最多4096个序列)
代码实现
/**
*
* @author Mr_Shang
*
* @version 1.0
*
*/
public class InstaIdGenerator {
protected static final Logger LOG = LoggerFactory.getLogger(IdWorker.class);
/**
* 时间戳的位数,实际占41位,最高位保持为0,保证long值为正数
*/
private int timestampBitCount = 42;
/**
* 逻辑分片位数
*/
private int regionBitCount = 10;
/**
* 逻辑分片的最大数量
*/
private int regionModelVal = 1 << regionBitCount;
/**
* 序列位数
*/
private int sequenceBitCount = 12;
/**
* 总的位数
*/
private int totalBitCount = timestampBitCount + regionBitCount + sequenceBitCount;
/**
* 当前序列值
*/
private long sequence = 0;
/**
* 最后一次请求时间戳
*/
private long lastTimestamp = -1L;
/**
* 序列的位板
*/
private long sequenceMask = -1L ^ (-1L << sequenceBitCount);
/**
* 最后一次请求用户标识
*/
private long lastTag=1L;
public InstaIdGenerator() {
}
public InstaIdGenerator(long seq) {
if (seq < 0) {
seq = 0;
}
this.sequence = seq;
}
public synchronized long nextId(long tag) {
long timestamp = timeGen();
if(tag<0){
tag=-tag;
}
if (timestamp < lastTimestamp) {
LOG.error(String.format("clock is moving backwards. Rejecting requests until %d.", 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;
}
if(tag==lastTag){
sequence = (sequence + 1) & sequenceMask;
if (sequence == 0) {
timestamp = tilNextMillis(lastTimestamp);
}
}
lastTag=tag;
lastTimestamp = timestamp;
return (timestamp << (totalBitCount - timestampBitCount))
| ((tag % regionModelVal) << (totalBitCount - timestampBitCount - regionBitCount)) | sequence;
}
}
完整源码地址
项目已经托管到github,飞机在这里☞ 数值型id生成器
参考内容
java id值_Java实现数值型ID生成器相关推荐
- java数值型转字符型_Java中数值型,字符型及字符串的相互转换
Java中数值型,字符型及字符串的相互转换由广州疯狂软件教育java培训分享: 刚开始学习Java不就前些时日被转换问题搞得有点凌乱在这里整理一下. 1.字符型与数值型之间的转换 (1)要将一个整数转 ...
- java 判断字符是否为数值型_java算法----判断字符串是否为数值型字符串
package com.huifudianxia.interview; import java.util.regex.Matcher; import java.util.regex.Pattern; ...
- Java范值_Java范型
定义类的时候,不为类的属性或方法的参数设置具体的类型,只使用一个标记表示,类使用的时候才动态地绑定一种数据类型,这就是范型. 如果应用使用了范型的类时没有指定类型,则会使用默认的类型Object. 1 ...
- java 注解值_java 注解默认值操作
我就废话不多说了,大家还是直接看代码吧~ package com.zejian.annotationdemo; import java.lang.annotation.ElementType; imp ...
- jgGrid获得的id值是主键的id而不是jqGrid的行号值
{name:'cityId',index:'cityId',sorttype:'int',width:0,hidden:true,key:true}, 一定要将你的主键值的的key设置为true,这样 ...
- Matlab中布尔值/逻辑值与数值型类型的相互转换
在涉及到一些下标运算时,经常会遇到布尔值与数值型的相互转换. 数值型转化为逻辑值 在MATLAB中常采用函数logical()将数值型数据转换成逻辑型数据.数值型数据转换成逻辑型的数据一般遵循这样的规 ...
- java还值_Java到底是引用传递还是值传递
前言 前段时间在群里看到类似这样一个问题,下面的代码会输出什么呢? public void test(){ String str = "hello"; change(str); S ...
- java默认值_Java中八种基本数据类型的默认值
通过一段代码来测试一下 8种基本数据类型的默认值 package dierge; public class Ceshi { int a; double b; boolean c; char d; fl ...
- java switch 值_Java switch多值匹配操作详解
这篇文章主要介绍了Java switch多值匹配操作详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 我们都知道 switch 用来走流程分支,大 ...
最新文章
- SAP零售:补货 Vs 多步骤补货
- 2.6 处理数据不匹配问题-深度学习第三课《结构化机器学习项目》-Stanford吴恩达教授
- 前端在linux中常用的命令,前端应该会的23个linux常用命令
- java中关于IO流的知识总结(重点介绍文件流的使用)
- Django中的反向解析
- oracle audit文件,[20191128]oracle Audit文件管理2.txt
- 平时喜欢使用的软件总结 欲善其事,必先利其器
- Win32 控件篇(2)
- pt5 mysql预处理_技术分享 | MySQL 监控利器之 Pt-Stalk
- ext2文件系统了解
- 漫画 | 为什么美国人发明了互联网?
- Typora官网下载慢,用这个镜像
- 最好用的Mac任务规划软件【滴答清单】
- boj 1348 网络流,从来没有一个网络流能让我如此泪流满面,这样的建图方式,仰慕dalong
- numpy.ones用法
- windows 安装vagrant reload 失败; No Virtualbox Guest Additions installation found.
- 持续造风,快手为品牌、商家提供“保姆式”服务
- p-sum结构解释+代码 二叉区间树
- 基类、派生类、虚基类、虚函数、虚析构、纯虚函数、抽象类
- 【蓝桥杯 路径 python】Dij算法
热门文章
- Windows IIS服务器安装(超详细)
- 在python集成开发环境中、可使用快捷键运行程序_在Python集成开发环境中,可使用快捷键 运行程序。_学小易找答案...
- 关于调用新浪支付接口
- 精编,精讲,精练,精益求精---AP微积分第10版在精雕细琢反复打磨中与你相遇
- 2021-4-8应用
- d3 - 建立力引导图将知识图谱可视化 (一)
- (转)智能投顾这么干才靠谱!BondIT获复星B轮投资
- GO语言中的循环语句
- 正反馈+负反馈还不够,还有【中性反馈】
- 【目标检测】|MicroNet