带你入门java雪花算法原理

带你入门java雪花算法原理

概述

雪花算法(Snowflake)是 Twitter 开源的分布式 id 生成算法,以其独特的 id 生成方式,广泛用于分布式系统中唯一 id 的生成,保证了分布式系统中数据的唯一性。

原理

雪花算法生成的 id 是一个 64 位的 long 型整数,其中:

  • 1 bit:表示不可用,Java long 类型的高位是符号位,正数是 0,负数是 1,在这里生成的都是数字,所以是 0。
  • 41 bit:表示毫秒时间戳,用于确保在分布式情况下生成的 id 是全局唯一的,41 bit 能表示的毫秒数大概是 69 年,从 1970 年到 2038 年不会出现时间戳重复问题。
  • 10 bit:表示工作机器 id,可以部署在 1024 台机器上,用于多机器生成 id 的情况下区分是哪台机器生成的 id。
  • 12 bit:表示同一毫秒时间戳内的序列号,用于保证同一毫秒时间戳生成的 id 不会重复。

实现

Java示例

下面是Java实现示例:

public class SnowflakeIdGenerator {
    // 定义起始时间戳,可根据需求更改此值为你们的系统投产时间
    private final static long START_STAMP = 1577808000000L;
    // 定义各位所占用的位数,共64位
    private final static long SEQUENCE_BIT = 12;
    private final static long MACHINE_BIT = 10;
    private final static long MAX_MACHINE_NUM = ~(-1L << MACHINE_BIT);
    private final static long MAX_SEQUENCE_NUM = ~(-1L << SEQUENCE_BIT);
    // 定义各位的位移,顺序很重要,否则会出错,从右到左,即从低位到高位
    private final static long MACHINE_LEFT = SEQUENCE_BIT;
    private final static long TIMESTAMP_LEFT = SEQUENCE_BIT + MACHINE_BIT;
    // 初始序列号
    private long sequence = 0L;
    private long lastStamp = -1L;
    private long machineId;
    /**
     * 构造函数
     * @param machineId 同一时间内生成多个ID时区分各个机器
     */
    public SnowflakeIdGenerator(long machineId) {
        if (machineId > MAX_MACHINE_NUM) {
            throw new RuntimeException("机器码超出最大值~~~");
        }
        this.machineId = machineId;
    }
    /**
     * 生成下一个ID
     * @return long
     */
    public synchronized long nextId() {
        long currStamp = getNewTimestamp();
        if (currStamp < lastStamp) {
            throw new RuntimeException("时间戳倒置:拒绝生成ID~~~");
        }
        if (currStamp == lastStamp) {
            sequence = (sequence + 1) & MAX_SEQUENCE_NUM;
            if (sequence == 0L) {
                currStamp = getNextTimestamp();
            }
        } else {
            sequence = 0L;
        }
        lastStamp = currStamp;
        return (currStamp - START_STAMP) << TIMESTAMP_LEFT| machineId << MACHINE_LEFT | sequence;
    }
    /**
     * 生成一个新的时间戳
     * @return long
     */
    private long getNewTimestamp() {
        return System.currentTimeMillis();
    }
    /**
     * 获取下一个时间戳,必须比当前时间戳大
     * @return
     */
    private long getNextTimestamp() {
        long timestamp = getNewTimestamp();
        while (timestamp <= lastStamp) {
            timestamp = getNewTimestamp();
        }
        return timestamp;
    }
}

示例说明

示例一

以下代码块展示了怎样使用 SnowflakeIdGenerator 类生成一个分布式系统的 id:

public static void main(String[] args) {
    SnowflakeIdGenerator snowflake = new SnowflakeIdGenerator(123L);
    long id = snowflake.nextId();
    System.out.println(id);
}

输出结果:

175691630939576320

示例二

以下代码块展示了怎样使用 SnowflakeIdGenerator 类生成两个分布式系统的 id,并比较它们的时间戳、机器码、序列号是否相同:

public static void main(String[] args) {
    SnowflakeIdGenerator snowflake = new SnowflakeIdGenerator(123L);
    long id1 = snowflake.nextId();
    long id2 = snowflake.nextId();
    long timestamp1 = (id1 >> 22) + 1577808000000L;
    long timestamp2 = (id2 >> 22) + 1577808000000L;
    long machine1 = (id1 >> 12) & 1023;
    long machine2 = (id2 >> 12) & 1023;
    long sequence1 = id1 & 4095;
    long sequence2 = id2 & 4095;
    System.out.println("id1: " + id1 + ", timestamp: " + timestamp1 + ", machine: " + machine1 + ", sequence: " + sequence1);
    System.out.println("id2: " + id2 + ", timestamp: " + timestamp2 + ", machine: " + machine2 + ", sequence: " + sequence2);
}

输出结果:

id1: 175691630939576320, timestamp: 1584055749065, machine: 123, sequence: 0
id2: 175691634581391872, timestamp: 1584055749289, machine: 123, sequence: 0

总结

通过上述示例,我们可以看出 Snowflake 算法生成分布式系统的 id 是非常简单、高效、可靠的。理解了 Snowflake 算法的原理和实现,我们可以在实际开发中使用 Snowflake 算法来生成分布式系统的唯一 id,保证数据的唯一性,避免出现数据重复问题。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:带你入门java雪花算法原理 - Python技术站

(0)
上一篇 2023年5月19日
下一篇 2023年5月19日

相关文章

  • Java日期操作方法工具类实例【包含日期比较大小,相加减,判断,验证,获取年份等】

    下面是详细讲解Java日期操作方法工具类实例的完整攻略。 一、概述 Java中日期操作是常见的需求,在很多场景中都需要对日期进行操作。Java日期操作方法工具类是为了方便Java开发者对日期进行操作而开发的一个工具类。该工具类提供了丰富的日期操作方法,包括比较大小、相加减、判断、验证、获取年份等。 二、使用方法 1. 引入工具类 首先,我们需要引入该工具类。…

    Java 2023年5月20日
    00
  • java(包括springboot)读取resources下文件方式实现

    下面是详细讲解“java(包括springboot)读取resources下文件方式实现”的完整攻略。 1. 背景 在Java中,经常需要读取resources下的文件。resources文件夹通常位于项目的classpath下,可以存放各种类型的文件,如文本文件、配置文件、图片等。这里将对读取resource文件夹下文件的几种常用方法进行讲解。 2. 使用…

    Java 2023年5月19日
    00
  • java实现超市管理系统

    Java实现超市管理系统攻略 超市管理系统利用了Java编程语言,可通过图形用户界面(GUI)使用。下面是该系统的完整攻略。 第一步:设计系统架构 在设计任何软件之前,我们必须首先确定系统的完整架构。超市管理系统需要设计以下要素: 一个用户登录界面 商品管理模块 库存管理模块 销售管理模块 支付管理模块 第二步:实现系统演示添加物品 接下来,我们将演示如何使…

    Java 2023年5月23日
    00
  • java 如何复制非空对象属性值

    要复制Java对象的非空属性值,可以使用Java自带的BeanUtils.copyProperties方法或Apache Commons BeanUtils框架中的copyProperties方法。 下面分别展示使用这两种方法复制Java对象的非空属性值的示例: 使用Java自带的BeanUtils.copyProperties方法 import org.a…

    Java 2023年5月26日
    00
  • 基于Spring Boot的Environment源码理解实现分散配置详解

    基于Spring Boot的Environment源码理解实现分散配置详解 什么是分散配置 分散配置(Decentralized Configuration)是指将应用程序的配置从中心化的配置中心中分发到多个不同的配置文件中,并在应用程序部署时进行组合。这种方式可以提高应用程序的可维护性和灵活性。Spring Boot提供了多种实现分散配置的方式,其中Env…

    Java 2023年5月19日
    00
  • 简单谈谈Java中String类型的参数传递问题

    关于Java中String类型的参数传递问题,我们从以下几个方面逐一展开讲解。 1. Java中的参数传递方式 Java中引用类型的参数传递是值传递的一种特殊形式。值传递是指将实际参数的值复制一份传递给函数,函数接收到的是实参值的一个副本,而不是实参值的引用。Java中对引用类型做值传递时其实是复制了一份引用,即一个指针类型的值传递到了方法中,引用的对象并没…

    Java 2023年5月27日
    00
  • asp.net实现的MVC跨数据库多表联合动态条件查询功能示例

    ASP.NET 实现的 MVC 跨数据库多表联合动态条件查询功能是一个常见的需求,可以通过以下的步骤来实现。 步骤一:建立数据库 首先需要在数据库中建立相应的表,以便进行多表联合查询。在本次示例中,我们将创建2个表,分别是 “users” 和 “orders” 表。其中 “users” 表中包含以下字段:id, name, email, password,”…

    Java 2023年5月19日
    00
  • JVM jstack实战之死锁问题详解

    JVM jstack实战之死锁问题详解 什么是死锁 死锁指的是两个或多个进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法继续执行下去。 如何检测死锁 在 Java 中,可以使用 jstack 命令检测死锁。使用指令 jstack <pid> 可以查看指定进程的堆栈信息, 进而分析出是否存在死锁。 如何解决死锁问题…

    Java 2023年5月27日
    00
合作推广
合作推广
分享本页
返回顶部