java雪花数据库长度_雪花算法(SnowFlake)Java实现
算法原理
SnowFlake算法生成id的结果是一个64bit大小的整数,它的结构如下图:
由于在Java中64bit的整数是long类型,所以在Java中SnowFlake算法生成的id就是long来存储的。
SnowFlake可以保证:
所有生成的id按时间趋势递增
整个分布式系统内不会产生重复id(因为有datacenterId和machineId来做区分)
算法实现(Java)
Twitter官方给出的算法实现 是用Scala写的,这里不做分析,可自行查看。
/**
* * SnowFlake的结构如下(每部分用-分开):
* * 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 -
* 000000000000
* * 1位标识,由于long基本类型在Java中是带符号的,最高位是符号位,正数是0,负数是1,所以id一般是正数,最高位是0
* * 41位时间截(毫秒级),注意,41位时间截不是存储当前时间的时间截,而是存储时间截的差值(当前时间截 - 开始时间截) *
* 得到的值),这里的的开始时间截,一般是我们的id生成器开始使用的时间,由我们程序来指定的(如下下面程序IdWorker类的startTime属性)。41位的时间截,可以使用69年,年T
* = (1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69
* * 10位的数据机器位,可以部署在1024个节点,包括5位datacenterId和5位workerId
* * 12位序列,毫秒内的计数,12位的计数顺序号支持每个节点每毫秒(同一机器,同一时间截)产生4096个ID序号
* * 加起来刚好64位,为一个Long型。
* *
* SnowFlake的优点是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由数据中心ID和机器ID作区分),并且效率较高,经测试,SnowFlake每秒能够产生20多万ID左右。
* [email protected] 80000636
*/
public class SnowflakeIdWorker {
private static final Logger logger = LoggerFactory.getLogger(SnowflakeIdWorker.class);
/**
* 起始的时间戳
*/
private final static long START_STMP = 1480166465631L;
/**
* 每一部分占用的位数
*/
private final static long SEQUENCE_BIT = 10; //序列号占用的位数
private final static long MACHINE_BIT = 5; //机器标识占用的位数
private final static long DATACENTER_BIT = 5;//数据中心占用的位数
/**
* 每一部分的最大值
*/
public final static long MAX_DATACENTER_NUM = -1L ^ (-1L << DATACENTER_BIT);
public final static long MAX_MACHINE_NUM = -1L ^ (-1L << MACHINE_BIT);
private final static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BIT);
/**
* 每一部分向左的位移
*/
private final static long MACHINE_LEFT = SEQUENCE_BIT;
private final static long DATACENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;
private final static long TIMESTMP_LEFT = DATACENTER_LEFT + DATACENTER_BIT;
private long datacenterId; //数据中心
private long machineId; //机器标识
private long sequence = 0L; //序列号
private long lastStmp = -1L;//上一次时间戳
/**
* 根据MAC生成datacenterId,根据MAC + PID生成machineId
*/
public SnowflakeIdWorker() {
long datacenterId = getDatacenterId(MAX_DATACENTER_NUM);
long machineId = getMachineId(datacenterId, MAX_MACHINE_NUM);
check(datacenterId, machineId);
this.datacenterId = datacenterId;
this.machineId = machineId;
}
/**
* datacenterId和machineId可配置
* @param datacenterId
* @param machineId
*/
public SnowflakeIdWorker(long datacenterId, long machineId) {
check(datacenterId, machineId);
this.datacenterId = datacenterId;
this.machineId = machineId;
}
private static void check(long datacenterId, long machineId) {
if (datacenterId > MAX_DATACENTER_NUM || datacenterId < 0) {
throw new EompRuntimeException(String.format("datacenterId can't be greater than %s or less than 0", MAX_DATACENTER_NUM));
}
if (machineId > MAX_MACHINE_NUM || machineId < 0) {
throw new EompRuntimeException(String.format("machineId can't be greater than %s or less than 0", MAX_MACHINE_NUM));
}
}
/**
* 产生下一个ID
*
* @return
*/
public synchronized long nextId() {
long currStmp = getNewstmp();
if (currStmp < lastStmp) {
throw new EompRuntimeException("Clock moved backwards. Refusing to generate id");
}
if (currStmp == lastStmp) {
//相同毫秒内,序列号自增
sequence = (sequence + 1) & MAX_SEQUENCE;
//同一毫秒的序列数已经达到最大
if (sequence == 0L) {
currStmp = getNextMill();
}
} else {
//不同毫秒内,序列号置为0
sequence = 0L;
}
lastStmp = currStmp;
return (currStmp - START_STMP) << TIMESTMP_LEFT //时间戳部分
| datacenterId << DATACENTER_LEFT //数据中心部分
| machineId << MACHINE_LEFT //机器标识部分
| sequence; //序列号部分
}
/**
* 阻塞到下一个毫秒,直到获得新的时间戳
* @return 当前时间戳
*/
private long getNextMill() {
long mill = getNewstmp();
while (mill <= lastStmp) {
mill = getNewstmp();
}
return mill;
}
/**
* 返回以毫秒为单位的当前时间
* @return 当前时间(毫秒)
*/
private long getNewstmp() {
return System.currentTimeMillis();
}
/**
* 机器标识
*/
private static long getMachineId(long datacenterId, long maxWorkerId) {
StringBuilder mpid = new StringBuilder();
mpid.append(datacenterId);
String name = ManagementFactory.getRuntimeMXBean().getName();
if (!name.isEmpty()) {
/** GET jvmPid */
mpid.append(name.split("@")[0]);
}
/** MAC + PID 的 hashcode 获取16个低位 */
return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1);
}
/**
* 数据标识id部分
*/
private static long getDatacenterId(long maxDatacenterId) {
long id = 0L;
try {
InetAddress ip = InetAddress.getLocalHost();
NetworkInterface network = NetworkInterface.getByInetAddress(ip);
if (network == null) {
id = 1L;
} else {
byte[] mac = network.getHardwareAddress();
id = ((0x000000FF & (long) mac[mac.length - 1])
| (0x0000FF00 & (((long) mac[mac.length - 2]) << 8))) >> 6;
id = id % (maxDatacenterId + 1);
}
} catch (Exception e) {
logger.error("getDatacenterId exception.", e);
}
return id;
}
/*public static void main(String[] args) {
long datacenterId = getDatacenterId(MAX_DATACENTER_NUM);
long machineId = getMachineId(datacenterId, MAX_MACHINE_NUM);
System.out.println("ip:" + datacenterId + ",processId:" + machineId);
}*/
}
测试类:
public class SnowflakeIdWorkerTest {
public static SetidSet = new HashSet<>();
public static void main(String[] args) {
SnowflakeIdWorker snowflakeIdWorker = new SnowflakeIdWorker(1, 0);
for (long i = 0; i < 1000; i++) {
new Thread(new Worker(snowflakeIdWorker)).start();
}
}
static class Worker implements Runnable {
private SnowflakeIdWorker snowflakeIdWorker;
public Worker(SnowflakeIdWorker snowflakeIdWorker) {
this.snowflakeIdWorker = snowflakeIdWorker;
}
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
Long id = snowflakeIdWorker.nextId();
if (!idSet.add(id)) {
System.err.println("存在重复id:" + id);
}
}
}
}
}
java雪花数据库长度_雪花算法(SnowFlake)Java实现相关推荐
- 堆排序算法java左程云_堆排序算法以及JAVA实现
堆的定义如下: n个元素的序列{k0,k1,...,ki,-,k(n-1)}当且仅当满足下关系时,称之为堆. " ki<=k2i,ki<=k2i+1;或ki>=k2i,ki ...
- java数据类型指定长度_判断(2分) Java的各种数据类型占用固定长度,与具体的软硬件平台环境无关...
参考答案如下 判断多选(3分) 下列有关我国公平责任的源流以及背景的说法正确的是 各定长度单选(2分) Which word stands for "pessimistic"?( ...
- java 基础 笔试题_非常全面的java基础笔试题
1.下列说法正确的是() (程序结构) A java程序的main方法必须写在类甩面 B java程序中可以有多个main方法 C.java程序中类名必须与文件名一样 D.JAVA程序的main方法中 ...
- Java ME游戏开发中,碰撞检测算法在Java?ME中的实现(
2019独角兽企业重金招聘Python工程师标准>>> 在Java ME游戏开发中,碰撞检测算法在Java?ME中的实现(百搜技术) 在Java ME游戏开发中,经常需要进行碰撞检测 ...
- python雪花下落代码_雪花算法python实现
雪花算法-Snowflake Snowflake是Twitter提出来的一个算法,其目的是生成一个64bit的整数: 1bit:一般是符号位,不做处理 41bit:用来记录时间戳,这里可以记录69年, ...
- Twitter的分布式自增ID算法snowflake (Java版)
概述 分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的. 有些时候我们希望能使用一种 ...
- java青蛙过河打字_趣味算法——青蛙过河(JAVA)
青蛙过河是一个非常有趣的智力游戏,其大意如下: 一条河之间有若干个石块间隔,有两队青蛙在过河,每队有3只青蛙,这些青蛙只能向前移动,不能向后移动,且一次只能有一只青蛙向前移动.在移动过程中,青蛙可以向 ...
- java路由方法_路由选择算法的JAVA实现.doc
路由选择算法的JAVA实现 路由选择算法的JAVA实现 第15卷第7期电脑开发与应用 路由选择算法的JAVA实现 JAVAImplementationofRouterSelectionAlgorith ...
- java引用数组长度_如何引用Java数组的长度
如何引用Java数组的长度 答:数组名.length 病人先有高热大汗.面赤.口渴饮.脉洪大,后突然出现面色苍白,四肢厥冷,脉微欲绝,此属于() 答:热证转寒 中国大学MOOC: 下列属于病原生物侵染 ...
最新文章
- 编程之美——2.7 求最大公约数
- python 来搞定 非线性方程组和最小二乘拟合问题
- 操作系统之进程管理:4、线程与多线程
- LeetCode 题 - 27. 移除元素 python实现
- 能量谱与功率谱(转自百度文库与维基百科)
- Linux 命令(47)—— file 命令
- vue Mutation 必须是同步函数 为什么_为什么vue组件中data必须用函数表达?
- Codeforces 448 D. Multiplication Table
- python:tushare pro 股票每日行情
- adb下载安装教程(已安装Android studio)
- LDA模型原理+代码+实操
- Maya材质球与渲染基础--Redshift,Arnold,Xgen
- MediaType介绍
- 如何读博士-2021.06.12
- 印度软件外包发展简记
- 使用百度翻译开发平台,英文翻译为中文
- 超实用的Mac快捷键神器:CheatSheet Mac中文免费版
- 小白尝试c++编写飞机大战
- PixiJS学习(8)预加载
- 计算机公共基础知识总结,计算机公共基础知识总结.docx