雪花算法(SnowFlake)-java
发布日期:2021-05-07 00:28:29 浏览次数:21 分类:技术文章

本文共 4675 字,大约阅读时间需要 15 分钟。

雪花算法

简介: 雪花算法 是 Twitter 开源的分布式id生成算法。使用一个64bit 的long型数字作为全局id。

优点:ID 自增,不会产生重复ID,在本地生成不会消耗网络效率高,存入数据库索引效率高。
缺点:依赖于系统时间的强一致性,如果系统时间回拨,或者改变,可能会造成生成重复id。

结构图如下:

雪花算法 数据结果图

  1. 1bit :该bit 不使用

    因为二进制中,最高位是符号位,1标识负数,0 标识 正数,生成的id 都是使用 正数标识,所以 该位 不使用,固定为 0.

  2. 41bit - 时间戳:

    41bit - 时间戳 = (当前时间戳(nowTimeMillis ) - 开始时间戳(beginTimeMillis))
    开始时间戳 :初始化的时候 是固定的,必须必nowTimeMillis 小。
    41bit 位 最多可表示 (2^41 - 1 )个数字,
    也就是 时间差为: (2^41 - 1 )个毫秒值,大概 69年多。

  3. 10bit : 包含 5 bit 数据中心 位 和 5 bit 机器位。

    即:最多可部署 2^5 (32)个 机房,
    每个机房 可以代表 2^5 (32)台机器。

  4. 12 bit:这个是用来记录同一个毫秒内产生的不同 id。

    即:同一毫秒 内 最多可以生产 2^12 -1 = 4095 个不同id,超过该值,必须要等倒下一毫秒才能继续生产id。

  5. 最后,将 以上 四部分,通过位移 加上 或 运算 组拼成一个 64 bit 位 的数值 即可。

  6. 核心 算法

    在这里插入图片描述

具体实现 如下

package com.nn.tools;/** * @ClassName Snow * @Author nn * @Date 2020/7/24 10:33 */public class MySnowFlake {
/** * 开始时间 */ private long beginTimeMillis = 1585644268888L; /** * 上一次 生产id 的时间 */ private long lastTimeMillis = -1L; /** * 当前时间 */ private long nowTimeMillis; /** * 机房id */ private long machineRoomId; /** * 机房 id 所占 位数(总 64位) */ private long machineRoomIdBits = 5L; /** * 最大 支持机房id值 即:2^5 -1 = 31 (0-31) */ private long maxMachineRoomId = -1L ^ (-1L << machineRoomIdBits); /** * 机器id */ private long machineId; /** * 机器id 所占 位数(总 64位) */ private long machineIdBits = 5L; /** * 最大 支持机器id值 即:2^5 -1 = 31 (0-31) */ private long maxMachineId = -1L ^ (-1L << machineRoomIdBits); /** * 一毫秒内 最多允许生成id 个数 所占位数 */ private long sequenceBits = 12L; /** * 一毫秒内 最多允许生成id 个数 * (2^12 - 1) = 4095 , 一毫秒内 最多允许生产 4095 个id * 超过该值时 进入等待,下一毫秒才可以继续生产 * -1L ---> 2进制为:1...(62位)...1 64位都为1 * -1L ^ (-1L << sequenceBits) = (2^12 - 1) = 4095 */ private long MaxSequenceNumInOneMs = -1L ^ (-1L << sequenceBits); /** * 代表一毫秒内生成的最新序号 */ private long sequenceNum; /** * 时间戳部分 需要左移 的位数;42 */ private long timeLeftBits = machineRoomIdBits + machineIdBits + sequenceBits; /** * 机房部分 需要左移 的位数;17 */ private long machineRoomLeftBits = machineIdBits + sequenceBits; /** * 机器部分 需要左移 的位数;12 */ private long machineLeftBits = sequenceBits; public MySnowFlake(long machineRoomId, long machineId) {
/** * 判断 输入的 machineRoomId 是否在[0-31]范围内 */ if (machineRoomId > maxMachineRoomId || machineRoomId < 0) {
throw new IllegalArgumentException( String.format("worker Id can't be greater than %d or less than 0", machineRoomId)); } /** * 判断 输入的 machineId 是否在[0-31]范围内 */ if (machineId > maxMachineId || machineId < 0) {
throw new IllegalArgumentException( String.format("datacenter Id can't be greater than %d or less than 0", machineId)); } this.machineRoomId = machineRoomId; this.machineId = machineId; } public synchronized long produceNextId() {
/** * 获取 当前 时间戳 */ nowTimeMillis = getNowTimeStamp(); if (lastTimeMillis == nowTimeMillis) {
/** * MaxSequenceNumInOneMs:sequenceNum 的 最大值 4095(2^12 - 1)其二进制为:0000 1111 1111 1111 * 当 sequenceNum = 4095 时(0000 1111 1111 1111) 加 1 得到-->2^12 (0001 0000 0000 0000) * 0001 0000 0000 0000 & 0000 1111 1111 1111 = 0 * * 即,当 sequenceNum = 0 的时候 就不能继续生产id,需要等待下一毫秒才可以继续生产id,即进入等待。 */ sequenceNum = (sequenceNum + 1) & MaxSequenceNumInOneMs; /** * 当某一毫秒的时间,产生的id数 超过4095,系统会进入等待,直到下一毫秒,系统继续产生ID */ if (sequenceNum == 0) {
nowTimeMillis = getNowTimeStamp(); while (nowTimeMillis == lastTimeMillis) {
nowTimeMillis = getNowTimeStamp(); } } } else {
sequenceNum = 0; } lastTimeMillis = nowTimeMillis; /** * id = 时间戳部分(41位) | 机房id(5位) | 机器id(5位) | 1 毫秒内 id序列号(12位) = 64 二进制位 值 */ long a = ((nowTimeMillis - beginTimeMillis) << timeLeftBits) | (machineRoomId << machineRoomLeftBits) | (machineId << machineLeftBits) | sequenceNum; return a; } /** * 获取当前时间戳 * * @return TimeMillis long */ private long getNowTimeStamp() {
return System.currentTimeMillis(); } public static void main(String[] args) {
MySnowFlake snow = new MySnowFlake(1, 1); for (int i = 0; i < 10000; i++) {
long l = snow.produceNextId(); System.out.println(l); } }}
上一篇:最全环境搭建-常用软件安装
下一篇:深入浅出 超详细 从 线程锁 到 redis 实现分布式锁(篇节 2)

发表评论

最新留言

路过,博主的博客真漂亮。。
[***.116.15.85]2025年03月19日 14时51分46秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章