IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> uuid生成器 -> 正文阅读

[嵌入式]uuid生成器

根据项目实际情况,参考雪花id生成算法写的,定位为嵌入式,可以用做分布式,针对单机多实例的情况做了优化兼容。

import java.lang.management.ManagementFactory;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 定位:为嵌入式uuid生成插件
 * 基于Twitter的Snowflake算法实现分布式高效有序ID生产
 * <p>
 * uuid结构如下:
 * 首位(保留)        时间戳(40位)                  机器id(10位)  进程id(10位)       序列号(3位)
 * 0    0000010000001101010100101100110000101100   0000000000     0000000000             001
 * <p>
 * 序列号3位:每毫秒做多支持8个id生成,单机tps最大:8*1000=8000tps
 * 进程id 10位,为支持单机多实例情况下可能机器id冲突问题
 * 机器id 10位:单机单实例最多支持1024个机器,单机多实例还需要除以实例数。
 * 时间戳40位;可以使用34年。这里的时间戳是与基准时间的时间差。
 * 生成的uuid是转换10进制后长度最多为19位。
 * <p>
 * 特性:
 * 1,解决跨毫秒起始值每次为0的情况
 * 2,支持根据mac地址和jvm线程id自动生成workerId和progressId
 * 3,允许小范围的(5ms)时间回拨
 * 4,支持项目单机多实例情况下的插件使用
 * <p>
 * 说明:
 * 进程id+机器id能大幅降级冲突的概率,尤其是单机多实例的情况下,但不能保证不重复的情况发生,最优解是手动分配。
 * <p>
 * 参考源码:
 * 外部:https://gitee.com/yu120/sequence(开源uuid生成项目)
 * 
 *
 * @author zhaolongbo3
 * @version 1.0
 * @description: 分号器
 * @date 2021/7/21 11:01
 */

public class UuidGenerator {
    /**
     * 私有化构造器
     */
    private UuidGenerator() {

    }


    /**
     * 使用系统默认的workerId和progressId,生成uuid
     *
     * @return
     */
    public static long getNextId() {
        return UuidInstance.INSTANCE.genUuid();
    }

    /**
     * 自定义机器id 和 进程id
     * 不传将使用默认生成的
     * @param workerId   机器id
     * @param progressId 进程id
     * @return
     */
    public static long getNextId(long workerId, long progressId) {
        return UuidInstance.INSTANCE.genUuid(workerId, progressId);
    }

    public static void main(String[] args) throws Exception {
        long start = System.currentTimeMillis();
        for (int i = 0; i < 8000; i++) {
            UuidGenerator.getNextId();
//            System.out.println("uuid:"+uuidGenerator.genUuid());
        }
        long end = System.currentTimeMillis();
        System.out.println("用时:" + (end - start));
    }


    private static class UuidInstance {
        /**
         * 64位序列号分配情况,标识位数
         */
        public static long sequenceBits = 3L;//序列号位数,每毫秒最多支持8个id,也就是单机tps 最多8000千
        public static long progressIdBits = 10L;//程序进程id位数,这里选择10位,是为了降低单机多实例情况下,生成的进程id冲突的情况。单机两实例,冲突概率约1/1000
        public static long workerIdBits = 10L;//机器id位数 10位最多支持1024个机器,也有冲突的可能性,机器id+线程id都冲突概率较低。
        public static long timestampBits = 40L;//时间戳位数,40位可以使用34年
        public static long blankBits = 1L;//首位1bit保留

        /**
         * mask防止溢出,位数控制
         */
        public static long progressIdMask = ~(-1L << (progressIdBits));//11111
        public static long workerIdMask = ~(-1L << workerIdBits);//1111111111
        public static long sequenceMask = ~(-1L << (sequenceBits));//11111

        /**
         * 左位数移动
         */
        public static long progressIdShift = sequenceBits;
        public static long workerIdShift = progressIdShift + progressIdBits;
        public static long timestampLeftShift = workerIdShift + workerIdBits;

        /**
         * 序列号
         */
        private long sequence = 0L;
        /**
         * 抖动值, 每一个新的毫秒抖动值变换一次(0,1), 如果不抖动则会导致每毫秒新生成的ID默认的sequence都为0, 那么每个ID最后一位都是偶数
         */
        private int vibrance = 0;

        /**
         * 基准时间点,确定后不能再更改
         */
        public static long twepoch = 1609430400000L; // (2021-01-01 00:00:00 GMT) 这一时刻的毫秒数,占 40 位。

        /**
         * 上次使用的时间戳
         */
        private long lastTimestamp = -1L;

        /**
         * 机器id(同一台服务器,id不变)
         */
        private long workerId = 0L;
        /**
         * 进程id
         */
        private long progressId = 0L;

        private Lock lock = new ReentrantLock();


        private static final UuidInstance INSTANCE = new UuidInstance();

        /**
         * 自动生成机器id和进程id
         * 参考mybatis-plus 算法:用mac地址生成workerID,用jvm进程PID生成progressId
         * 源码地址:https://gitee.com/baomidou/mybatis-plus/blob/3.0/mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/toolkit/Sequence.java
         * @throws Exception
         */ {
            try {
                // mac地址
                byte[] macAddress = NetworkInterface.getByInetAddress(InetAddress.getLocalHost()).getHardwareAddress();
                if (macAddress == null || macAddress.length < 2) {
                    throw new RuntimeException("UuidGenerator:get macAddress error!");
                }
                /**
                 * 0x000000FF=255=11111111,8位
                 * 0x0000FF00=1111111100000000,16位
                 * 或运算后最大1111111111111111=65535 右移6位 结果最大1023
                 */
                workerId = (((0x000000FF & (long) macAddress[macAddress.length - 2]) | (0x0000FF00 & (((long) macAddress[macAddress.length - 1]) << 8))) >> 6) % (workerIdMask + 1);
//                jvm进程地址
                String name = ManagementFactory.getRuntimeMXBean().getName();
                StringBuilder sb = new StringBuilder();
                sb.append(workerId);
                if(null == name || "".equals(name)){
                    sb.append(name.split("@")[0]);
                }
                int hashCode = sb.toString().hashCode();
                int i = hashCode & 0xffff;//0xffff=1111111111111111
                progressId = i % (progressIdMask + 1);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

        private long genUuid() {
            return nextId();
        }


        private long genUuid(long workerId, long progressId) {
            if (progressId != 0L) {
                this.progressId = progressId;
            }
            if (workerId != 0L) {
                this.workerId = workerId;
            }
            return nextId();
        }

        private long nextId() {

            lock.lock();
            try {
                long timestamp = getTimestamp();
//              时间回拨校验
                timestamp = checkTime(timestamp);
//              如果还在当前毫秒内,序列号增加,如果序列号达到最大,等到到下一毫秒
                if (lastTimestamp == timestamp) {
                    sequence = (sequence + 1) & sequenceMask;
                    if (sequence == 0) {
                        timestamp = tilNextMillis(lastTimestamp);
                    }
                } else {
//                  不在当前毫秒内,序列号从0或者1开始
                    this.sequence = ~vibrance & 1;
                }
                lastTimestamp = timestamp;

                return ((timestamp - twepoch) << timestampLeftShift)
                        | (workerId & workerIdMask) << workerIdShift
                        | (progressId & progressIdMask) << progressIdShift
                        | sequence;
            } finally {
                lock.unlock();
            }

        }

        private long checkTime(long timestamp) {
            if (timestamp < lastTimestamp) {
                long offset = lastTimestamp - timestamp;
                if (offset <= 5) {
                    try {
                        //时间偏差大小小于5ms,则等待两倍时间
                        wait(offset << 1);//wait
                        timestamp = getTimestamp();
                        if (timestamp < lastTimestamp) {
                            //还是小于,抛异常并上报
                            throw new RuntimeException(String.format("uuid gen error ,time return back for %d millisecond", lastTimestamp - timestamp));
                        }
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                } else {
                    //throw
                    throw new RuntimeException(String.format("uuid gen error ,time return back for %d millisecond", lastTimestamp - timestamp));

                }
            }
            return timestamp;
        }

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

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


    }
}

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-07-30 12:54:10  更:2021-07-30 12:55:14 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/9 1:30:22-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码