Java实现雪花算法的工具类介绍

 更新时间:2023年05月23日 16:13:12   作者:三省同学  
雪花 (SnowFlake )算法是一种分布式唯一ID生成算法,可以生成全局唯一的ID标识符,就像自然界中雪花一般没有相同的雪花,本文和大家分享了一个雪花算法工具类,需要的可以收藏一下

简介

雪花 (SnowFlake )算法是一种分布式唯一ID生成算法,可以生成全局唯一的ID标识符,就像自然界中雪花一般没有相同的雪花。它的核心思想是将一个64位的整数分成4部分,分别是:

  • 1位标识符:即最高位,始终为0,用于区分正数和负数。
  • 41位时间戳:表示生成ID的时间戳,精确到毫秒级别,可以使用69年。
  • 10位数据中心ID:表示数据中心的编号,可以支持1024个数据中心。
  • 12位机器ID:表示机器的编号,可以支持4096台机器。

snowflake生成的ID整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由datacenter和workerId作区分),并且效率较高。

在同一毫秒内,不同的机器或数据中心可以生成不同的序列号,通过这种方式保证了生成的ID的唯一性。另外,由于时间戳占据了64位整数的高位部分,因此生成的ID是越来越大的,可以满足一些需要按照时间顺序排序的场景需求。

雪花算法的优点在于:

  • 简单易实现:主要依赖于时间戳、数据中心ID和机器ID三个参数,实现起来比较简单。
  • 唯一性:生成的ID具有全局唯一性,可以满足分布式系统的需求。
  • 时间有序:生成的ID是按照时间有序递增的,可以满足一些需要按照时间顺序排序的场景需求,存入数据库中,索引效率高。。
  • 可扩展性:可以根据需要增加数据中心ID和机器ID的位数,支持更多的数据中心和机器。
  • 高性能高可用:生成时不依赖于数据库,完全在内存中生成。
  • 容量大:每秒中能生成数百万的自增ID。

但是,雪花算法也存在一些缺点:

  • 依赖于系统时钟:如果系统时钟回拨,则可能会生成重复的ID。
  • 数据中心ID和机器ID需要手动分配:需要手动配置数据中心ID和机器ID,不太方便管理。
  • 机器编号有限:12位机器ID只能支持4096台机器,如果需要支持更多的机器,则需要增加机器ID的位数。

综上所述,雪花算法是一种简单易实现、具有唯一性和时间有序性的分布式ID生成算法,适用于分布式系统中的唯一ID标识符的生成。

Java实现

public class Snowflake {
    // 开始时间戳,一般为项目启动时间
    private final long twepoch = 1288834974657L;
    // 机器ID所占的位数
    private final long workerIdBits = 5L;
    // 数据标识ID所占的位数
    private final long datacenterIdBits = 5L;
    // 支持的最大机器ID,结果是31
    private final long maxWorkerId = ~(-1L << workerIdBits);
    // 支持的最大数据标识ID,结果是31
    private final long maxDatacenterId = ~(-1L << datacenterIdBits);
    // 序列号所占的位数
    private final long sequenceBits = 12L;
    // 机器ID向左移12位
    private final long workerIdShift = sequenceBits;
    // 数据标识ID向左移17位(12+5)
    private final long datacenterIdShift = sequenceBits + workerIdBits;
    // 时间戳向左移22位(5+5+12)
    private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
    // 生成序列的掩码,这里是4095
    private final long sequenceMask = ~(-1L << sequenceBits);

    private long workerId; // 机器ID
    private long datacenterId; // 数据标识ID
    private long sequence = 0L; // 序列号
    private long lastTimestamp = -1L; // 上次生成ID的时间戳

    public Snowflake(long workerId, long datacenterId) {
        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;
    }

    public synchronized long nextId() {
        long timestamp = timeGen();

        if (timestamp < 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; // 序列号重置为0
        }

        lastTimestamp = timestamp;

        return ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | sequence;
    }

    private long tilNextMillis(long lastTimestamp) {
        long timestamp = timeGen();
        while (timestamp <= lastTimestamp) {
            timestamp = timeGen();
        }
        return timestamp;
    }

    private long timeGen() {
        return System.currentTimeMillis();
    }

    public static void main(String[] args) {
        Snowflake idWorker = new Snowflake(0, 0);
        for (int i = 0; i < 1000; i++) {
            long id = idWorker.nextId();
            System.out.println(Long.toBinaryString(id));
            System.out.println(id);
        }
    }
}

Java相关工具类

Java版Snowflake开源库比较多,以下是一些常用的开源库及其使用方式:

1.Twitter的snowflake:是雪花算法最早的Java实现版本,支持高并发、低延迟、高可用等特点。使用方式:

Snowflake snowflake = new Snowflake(workerId, datacenterId);
long id = snowflake.nextId();

2.百度的UidGenerator:是基于Twitter的snowflake算法改进而来的,支持高性能、高可用、高并发等特点。使用方式:

UidGenerator uidGenerator = UidGenerator.getUidGenerator();
long id = uidGenerator.getUID();

3.美团的Leaf:是一款高性能、轻量级的分布式ID生成器,支持多种ID生成算法,包括Snowflake算法。使用方式:

SegmentIDGenImpl idGen = new SegmentIDGenImpl();
idGen.init();
long id = idGen.getId();

4.阿里巴巴的nacos:是一款轻量级的服务注册与发现工具,其中包含了雪花算法的Java实现版本。使用方式:

SnowFlake snowFlake = new SnowFlake(dataCenterId, machineId);
long id = snowFlake.nextId();

5.yitter

6.hutool工具类

Snowflake snowflake = IdUtil.getSnowflake(1, 1);
long id = snowflake.nextId();

到此这篇关于Java实现雪花算法的工具类介绍的文章就介绍到这了,更多相关Java雪花算法内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Feign 使用HttpClient和OkHttp方式

    Feign 使用HttpClient和OkHttp方式

    这篇文章主要介绍了Feign 使用HttpClient和OkHttp方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10
  • Java类加载异常:java.lang.ClassNotFoundException解决方法

    Java类加载异常:java.lang.ClassNotFoundException解决方法

    这篇文章主要给大家介绍了关于Java类加载异常:java.lang.ClassNotFoundException的解决方法,异常是Java编程语言中的一个标准异常类,它继承自类,当在运行时尝试加载类时,如果系统找不到指定的类文件就会抛出该异常,需要的朋友可以参考下
    2023-11-11
  • java查询mongodb中的objectid示例

    java查询mongodb中的objectid示例

    这篇文章主要介绍了java查询mongodb中的objectid示例,需要的朋友可以参考下
    2014-04-04
  • java客户端Jedis操作Redis Sentinel 连接池的实现方法

    java客户端Jedis操作Redis Sentinel 连接池的实现方法

    下面小编就为大家带来一篇java客户端Jedis操作Redis Sentinel 连接池的实现方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-03-03
  • Java 实现常见的非对称加密算法

    Java 实现常见的非对称加密算法

    这篇文章主要介绍了Java 实现常见的非对称加密算法,帮助大家更好的理解和使用Java,感兴趣的朋友可以了解下
    2020-11-11
  • MyBatis处理mysql主键自动增长出现的不连续问题解决

    MyBatis处理mysql主键自动增长出现的不连续问题解决

    本文主要介绍了MyBatis处理mysql主键自动增长出现的不连续问题解决,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-09-09
  • Java 将PPT幻灯片转为HTML文件的实现思路

    Java 将PPT幻灯片转为HTML文件的实现思路

    本文以Java程序代码为例展示如何通过格式转换的方式将PPT幻灯片文档转为HTML文件,本文通过实例代码图文相结合给大家分享实现思路,需要的朋友参考下吧
    2021-06-06
  • Spring中校验器(Validator)的深入讲解

    Spring中校验器(Validator)的深入讲解

    Spring校验器,参数校验从此简单。下面这篇文章主要给大家介绍了关于Spring中校验器(Validator)的相关资料,文中通过示例代码介绍非常详细,需要的朋友可以参考借鉴,下面随着小编来一起学习学习吧
    2018-06-06
  • 浅析SpringBoot自动装配的实现

    浅析SpringBoot自动装配的实现

    springboot开箱即用,其实实现了自动装配,本文重点给大家介绍SpringBoot是如何做到自动装配的,感兴趣的朋友跟随小编一起看看吧
    2022-02-02
  • 9种Java单例模式详解(推荐)

    9种Java单例模式详解(推荐)

    这篇文章主要介绍了9种Java单例模式详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-03-03

最新评论