ID雪花算法

本文详细介绍了雪花算法的工作原理,包括时间戳、机器ID和序列号的组合方式,以及如何确保ID的唯一性和有序性。通过Java实现了一个IdWorker类,用于生成基于雪花算法的唯一ID。此外,还提供了获取机器ID和数据中心ID的方法,确保了在分布式环境中的应用。
摘要由CSDN通过智能技术生成

雪花算法

package com.zkdn.common.utils;

import org.springframework.stereotype.Component;

import java.lang.management.ManagementFactory;
import java.net.InetAddress;
import java.net.NetworkInterface;
@Component
public class IdWorker {

// 时间起始标记点,作为基准,一般取系统的最近时间(一旦确定不能变动)po;
private final static long twepoch = 1288834974657L;
// 机器标识位数
private final static long workerIdBits = 5L;
// 数据中心标识位数
private final static long datacenterIdBits = 5L;
// 机器ID最大值
private final static long maxWorkerId = -1L ^ (-1L << workerIdBits);
// 数据中心ID最大值

private final static long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
// 毫秒内自增位
private final static long sequenceBits = 12L;
// 机器ID偏左移12位

private final static long workerIdShift = sequenceBits;

// 数据中心ID左移17位
private final static long datacenterIdShift = sequenceBits + workerIdBits;

// 时间毫秒左移22位
private final static long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;

private final static long sequenceMask = -1L ^ (-1L << sequenceBits);
/* 上次生产id时间戳 */
private static long lastTimestamp = -1L;
// 0,并发控制
private long sequence = 0L;

private final long workerId;
// 数据标识id部分
private final long datacenterId;

public IdWorker(){
    this.datacenterId = getDatacenterId(maxDatacenterId);
    this.workerId = getMaxWorkerId(datacenterId, maxWorkerId);
}
/**
 * @param workerId
 *            工作机器ID
 * @param datacenterId
 *            序列号
 */
public IdWorker(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;
}
/**
 * 获取下一个ID
 *
 * @return
 */
public synchronized long nextId(Long id) {
    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) {
        // 当前毫秒内,则+1
        sequence = (sequence + 1) & sequenceMask;
        if (sequence == 0) {
            // 当前毫秒内计数满了,则等待下一秒
            timestamp = tilNextMillis(lastTimestamp);
        }
    } else {
        sequence = 0L;
    }
    lastTimestamp = timestamp;
    // ID偏移组合生成最终的ID,并返回ID
    long nextId = ((timestamp - twepoch) << timestampLeftShift)
            | (datacenterId << datacenterIdShift)
            | (workerId << workerIdShift) | sequence;

    return nextId;
}

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

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

/**
 * <p>
 * 获取 maxWorkerId
 * </p>
 */
protected static long getMaxWorkerId(long datacenterId, long maxWorkerId) {
    StringBuffer mpid = new StringBuffer();
    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);
}

/**
 * <p>
 * 数据标识id部分
 * </p>
 */
protected 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) {
        System.out.println(" getDatacenterId: " + e.getMessage());
    }
    return id;
}

public String nextId(){
    return String.valueOf(nextId(1L));
}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值