All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.gitee.cn9750wang.webtools.utils.SnowFlakeIdGenerator Maven / Gradle / Ivy

The newest version!
/*
 *    Copyright 2021 wwy
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package com.gitee.cn9750wang.webtools.utils;

import com.gitee.cn9750wang.webtools.error.defines.ParamErr;

/**
 * 雪花算法ID生成器
 * 生成的ID由 1bit符号位 + 41bit时间偏移量 + 5bit数据中心ID + 5bit机器ID + 12bit序列号 组成
 * 其中 5bit数据中心ID+5bit机器ID 组成服务器ID,服务器ID总计1024个
 * @author wwy
 */
public class SnowFlakeIdGenerator {

    /**
     * 服务器id
     * 由 5bit数据中心ID+5bit机器ID 组成服务器ID
     */
    private final long serverId;

    /** 12位的序列号 */
    private long sequence = -1;

    /** 初始时间戳 2020-01-01 */
    private static final long START_TIMESTAMP = 1577808000000L;
    /** 上一次获取的时间戳 */
    private long lastTimestamp = 0;


    /** 递增序号 长度 */
    private static final long SEQUENCE_SIZE = 12;
    /** 数据中心ID或机器ID 长度 */
    private static final long DATA_CENTER_ID_SIZE = 5;
    /** 服务器ID 长度 */
    private static final long SERVER_ID_SIZE = DATA_CENTER_ID_SIZE * 2;
    /** 时间戳 长度 */
    private static final long TIMESTAMP_SIZE = 41;

    /** 零 */
    private static final byte ZERO = 0;
    /** 服务器ID最大值 */
    private static final short MAX_SERVER_ID = 1 << SERVER_ID_SIZE - 1;
    /** 数据中心ID或机器ID最大值 */
    private static final byte MAX_DATA_CENTER_ID = 1 << DATA_CENTER_ID_SIZE - 1;
    /** 递增序号最大值 */
    private static final short MAX_SEQUENCE = 1 << SEQUENCE_SIZE - 1;

    /** 时间戳裁剪 */
    private static final long TIMESTAMP_CUT = ~(-1L << TIMESTAMP_SIZE);
    /** 时间戳左移值 */
    private static final long TIMESTAMP_LEFT_SHIFT = SERVER_ID_SIZE + SEQUENCE_SIZE;

    private SnowFlakeIdGenerator(final int serverId){
        this.serverId = (long) serverId << SEQUENCE_SIZE;
    }

    /**
     * 获取雪花ID生成器
     * @param serverId 服务器ID 10bit组成
     * @return 雪花ID生成器
     */
    public static SnowFlakeIdGenerator getInstance(final int serverId){
        if(serverId < ZERO || serverId > MAX_SERVER_ID){
            checkValueBetweenThrow("serverId", MAX_SERVER_ID);
        }
        return new SnowFlakeIdGenerator(serverId);
    }

    /**
     * 获取雪花ID生成器
     * @param dataCenterId 数据中心ID 5bit组成
     * @param workerId 机器ID 5bit组成
     * @return 雪花ID生成器
     */
    public static SnowFlakeIdGenerator getInstance(final int dataCenterId,final int workerId){
        if(dataCenterId < ZERO || dataCenterId > MAX_DATA_CENTER_ID){
            checkValueBetweenThrow("dataCenterId", MAX_DATA_CENTER_ID);
        }

        if(workerId < ZERO || workerId > MAX_DATA_CENTER_ID){
            checkValueBetweenThrow("workerId", MAX_DATA_CENTER_ID);
        }
        int serverId = dataCenterId;
        serverId <<= 5;
        serverId += workerId;
        return getInstance(serverId);
    }



    /** 生成异常对象 */
    private static void checkValueBetweenThrow(String valueName, long max){
        ParamErr.BETWEEN.format(valueName,SnowFlakeIdGenerator.ZERO,max).throwErr();
    }

    /**
     * 获取雪花算法生成的ID
     * @return 雪花算法生成的ID
     */
    public long nextId() {
        // 获取时间戳
        final var timestamp = System.currentTimeMillis() - START_TIMESTAMP;
        // 服务器计数器
        final long sequence;
        // 对象加锁,校验时间戳和设置计数器
        synchronized (this){
            // 如果时间戳小于上次的时间戳
            if(timestamp < this.lastTimestamp){
                throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds",lastTimestamp));
            }
            // 如果与上次时间戳相等,序号自增
            if(timestamp == this.lastTimestamp){
                this.sequence++;
                // 掐头,掐去超出12位的部分
//                this.sequence &= (Short.MAX_VALUE ^ (Short.MAX_VALUE << 12));
                if(this.sequence > MAX_SEQUENCE){
                    try {
                        Thread.sleep(0);
                    }catch (InterruptedException e){
                        e.printStackTrace();
                    }
                    return nextId();
                }
            }
            // 否则重新计数
            else {
                this.sequence = 0;
            }
            // 刷新时间戳
            this.lastTimestamp = timestamp;
            sequence = this.sequence;
        }
        // 41bit时间戳,先 左移22位
        final var timestamp41bit = (timestamp & TIMESTAMP_CUT) << TIMESTAMP_LEFT_SHIFT;
        // 计算雪花算法得到的值
        return timestamp41bit | serverId | sequence;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy