雪花算法之唯一ID生成器理解

雪花算法基本情况

  • 雪花算法是一个分布式的唯一ID生成器。
  • 它应该具有高并发,以及高性能优点。
  • 基于时间戳,ID具有有序性,同时分布式下机器间时间差异过大(类似同一台机器时间回拨,一定会重复),会导致重复ID。
  • 基于机器码和操作中心id,ID具有不可重复性。
  • 它的ID是8字节64bit的一个Long长整型数据。

ID基本组成

ID基本组成:
不用: 1bit,因为最高位是符号位,0表示正,1表示负,所以这里固定为0
时间戳: 41bit,服务上线的时间毫秒级的时间戳(为当前时间-服务第一次上线时间),这里为(2^41-1)/1000/60/60/24/365 = 49.7年
工作机器id: 10bit,表示工作机器id,用于处理分布式部署id不重复问题,可支持2^10 = 1024个节点
序列号: 12bit,用于离散同一机器同一毫秒级别生成多条Id时,可允许同一毫秒生成2^12 = 4096个Id,则一秒就可生成4096*1000 = 400w个Id

在这里插入图片描述
这样看,在分布式时,通过时间戳+工作机器ID+散列序列号,几乎不会重复,当然你必须保证工作机器ID的准确配置。

源码简易分析以及注意事项

我们以mybatisplus实现的雪花算法为例:

  • IdWorker类:
    注意:DefaultIdentifierGenerator()这个必须是单例模式的,否者在多线程高并发下,会有重复ID,而且很多。详见IDENTIFIER_GENERATOR.nextId(entity)这个方法实现
package com.baomidou.mybatisplus.core.toolkit;

import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator;
import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;

public class IdWorker {
	/**单例模式,否者会多个重复Id,
	详见IDENTIFIER_GENERATOR.nextId(entity).longValue()*/
    private static IdentifierGenerator IDENTIFIER_GENERATOR = new DefaultIdentifierGenerator();
    public static final DateTimeFormatter MILLISECOND = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS");

    public IdWorker() {
    }
	/**获取Id*/
    public static long getId() {
        return getId(new Object());
    }
	/**获取Id,最终都会走这一步*/
    public static long getId(Object entity) {
        return IDENTIFIER_GENERATOR.nextId(entity).longValue();
    }

	/**机器码和数据中心的ID,参数不能重复*/
    public static void initSequence(long workerId, long dataCenterId) {
        IDENTIFIER_GENERATOR = new DefaultIdentifierGenerator(workerId, dataCenterId);
    }
}
  • IDENTIFIER_GENERATOR.nextId(entity).longValue() 方法
    nextId是一个线程安全的方法,这也是多线程唯一Id生成的必要之一。
    synchronized并不会直接转成重量级锁,因为java在1.6已经优化,因此在资源上没有过分占用,是从偏向锁,轻量级锁,再到重量级锁的过程。
 public synchronized long nextId() {
		 /** long timestamp = this.timeGen();这步代码一定要注意当你DefaultIdentifierGenerator是多例时,这里获取的timestamp不具有真正的唯一性,因为多个实例一起在工作,所以写工具类时不要写成多例 */
        long timestamp = this.timeGen();

		// 这里是时间异常,针对分布式下,不同机器时间的差异过大
        if (timestamp < this.lastTimestamp) {
            long offset = this.lastTimestamp - timestamp;
            if (offset > 5L) {
                throw new RuntimeException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", offset));
            }

            try {
                this.wait(offset << 1);
                timestamp = this.timeGen();
                if (timestamp < this.lastTimestamp) {
                    throw new RuntimeException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", offset));
                }
            } catch (Exception var6) {
                throw new RuntimeException(var6);
            }
        }

        if (this.lastTimestamp == timestamp) {
            this.sequence = this.sequence + 1L & 4095L;
            if (this.sequence == 0L) {
            	// 散列序列号没了,必须转到下一毫秒,采用阻塞
                timestamp = this.tilNextMillis(this.lastTimestamp);
            }
        } else {
       		//  散列序列号
            this.sequence = ThreadLocalRandom.current().nextLong(1L, 3L);
        }

        this.lastTimestamp = timestamp;
        // 或运算连接运算后的时间戳,数据中心,工作中心,序列号的bit位,会被自动返回为一个长整型的数据。
        return timestamp - 1288834974657L << 22 | this.datacenterId << 17 | this.workerId << 12 | this.sequence;
    }

雪花算法很好用,让我了解了更多的东西,学习了。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java雪花算法是一种分布式id生成算法,它使用一个64位的long型数字作为全局唯一id。该算法基于时间戳和序列号自增的方式,可以在高并发分布式环境下生成不重复的id,每秒可生成百万个不重复的id。此算法简单且高效,不依赖于第三方库或中间件。因此,使用Java雪花算法可以轻松实现全局唯一id生成。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [ID生成方式Java——雪花算法](https://blog.csdn.net/qq_42900213/article/details/126172808)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [SnowFlake 雪花算法详解与实现](https://blog.csdn.net/chenlixiao007/article/details/123956128)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [java 雪花算法生成ID](https://blog.csdn.net/qq_37996327/article/details/105650644)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值