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

com.gitee.huanminabc.utils_common.base.SnowIdUtil Maven / Gradle / Ivy

There is a newer version: 1.0.5-RELEASE
Show newest version
package com.gitee.huanminabc.utils_common.base;


/**
 *
 * 单例模式的雪花id
 * @Description:
 * Twitter_Snowflake
* SnowFlake的结构如下(每部分用-分开):
* 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000
* 1位标识,由于long基本类型在Java中是带符号的,最高位是符号位,正数是0,负数是1,所以id一般是正数,最高位是0
* 41位时间截(毫秒级),注意,41位时间截不是存储当前时间的时间截,而是存储时间截的差值(当前时间截 - 开始时间截) * 得到的值),这里的的开始时间截,一般是我们的id生成器开始使用的时间,由我们程序来指定的(如下下面程序IdWorker类的startTime属性)。41位的时间截,可以使用69年,年T = (1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69
* 10位的数据机器位,可以部署在1024个节点,包括5位datacenterId和5位workerId
* 12位序列,毫秒内的计数,12位的计数顺序号支持每个节点每毫秒(同一机器,同一时间截)产生4096个ID序号
* 加起来刚好64位,为一个Long型。
* SnowFlake的优点是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由数据中心ID和机器ID作区分),并且效率较高,经测试,SnowFlake每秒能够产生200万~500万ID左右。 和机器性能有关 * 我电脑500万id只需要1.249秒 */ public class SnowIdUtil { /** * 私有的 静态内部类 */ private static class SnowFlake { /** * 内部类对象(单例模式) */ private static final SnowFlake SNOW_FLAKE = new SnowFlake(); /** * 起始的时间戳 */ private final long START_TIMESTAMP = 1557489395327L; /** * 序列号占用位数 */ private final long SEQUENCE_BIT = 12; /** * 机器标识占用位数 */ private final long MACHINE_BIT = 10; /** * 时间戳位移位数 */ private final long TIMESTAMP_LEFT = SEQUENCE_BIT + MACHINE_BIT; /** * 最大序列号 (4095) */ private final long MAX_SEQUENCE = ~(-1L << SEQUENCE_BIT); /** * 最大机器编号 (1023) */ private final long MAX_MACHINE_ID = ~(-1L << MACHINE_BIT); /** * 生成id机器标识部分 */ private long machineIdPart; /** * 序列号 */ private long sequence = 0L; /** * 上一次时间戳 */ private long lastStamp = -1L; /** * 构造函数初始化机器编码 */ private SnowFlake() { //模拟这里获得本机机器编码 long localIp = 4321; //localIp & MAX_MACHINE_ID最大不会超过1023,在左位移12位 machineIdPart = (localIp & MAX_MACHINE_ID) << SEQUENCE_BIT; } /** * 获取雪花ID */ public synchronized long nextId() { long currentStamp = timeGen(); //避免机器时钟回拨 while (currentStamp < lastStamp) { // //服务器时钟被调整了,ID生成器停止服务. throw new RuntimeException(String.format("时钟已经回拨. Refusing to generate id for %d milliseconds", lastStamp - currentStamp)); } if (currentStamp == lastStamp) { // 每次+1 sequence = (sequence + 1) & MAX_SEQUENCE; // 毫秒内序列溢出 if (sequence == 0) { // 阻塞到下一个毫秒,获得新的时间戳 currentStamp = getNextMill(); } } else { //不同毫秒内,序列号置0 sequence = 0L; } lastStamp = currentStamp; //时间戳部分+机器标识部分+序列号部分 return (currentStamp - START_TIMESTAMP) << TIMESTAMP_LEFT | machineIdPart | sequence; } /** * 阻塞到下一个毫秒,直到获得新的时间戳 */ private long getNextMill() { long mill = timeGen(); // while (mill <= lastStamp) { mill = timeGen(); } return mill; } /** * 返回以毫秒为单位的当前时间 */ protected long timeGen() { return System.currentTimeMillis(); } } /** * 获取long类型雪花ID */ public static long uniqueLong() { return SnowFlake.SNOW_FLAKE.nextId(); } /** * 获取String类型雪花ID */ public static String uniqueLongHex() { return String.format("%016x", uniqueLong()); } /** * 场景数据库水平分库 水平分表 或者搜索引擎分片存储 .... * 分布式-切片(用户的雪花id+取摸=分片位置) * 假设你有3个分片那么就是取摸3 结果只能是 0 1 2 * 假设你有4个分片那么就是取摸4 结果只能是 0 1 2 3 * ................ * @param snowId 雪花id * @param zoneSize */ public static Long slicePosition(long snowId,int zoneSize){ if (zoneSize==0) { zoneSize=1; } if (snowId==0) { return 0L; } return snowId%zoneSize; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy