雪花算法生成id

SnowFlake算法生成id的结果是一个64bit大小的整数,它的结构如下图:

雪花算法生成id_第1张图片
雪花生成的id有64位,其中第1位是符号位,第2至42位是41位的时间戳,第42位至52位是10位的工具机器,包括5位数据中心和5位机器id,第53位到64位是12位的序列号。

SnowFlake可以保证:
● 所有生成的id按时间趋势递增
● 整个分布式系统内不会产生重复id(因为有datacenterId和workerId来做区分)

具体实现的代码如下:

package org.xiaov.bean;

import org.xiaov.bean.date.DatePattern;

/**
 * 

* *

* * @author xiaovcloud * @since 2021/7/17 15:20 */
public class Snowflake { /** * 起始的时间戳 2021/01/01 */ private final static long START_STMP = DatePattern.START_STMP; /** * 每一部分占用的位数 */ private final static long MACHINE_BIT = 5; //机器标识占用的位数 private final static long DATACENTER_BIT = 5;//数据中心占用的位数 private final static long SEQUENCE_BIT = 12; //序列号占用的位数 /** * 每一部分的最大值 */ private final static long MAX_DATACENTER_NUM = ~(-1L << DATACENTER_BIT); private final static long MAX_MACHINE_NUM = ~(-1L << MACHINE_BIT); private final static long MAX_SEQUENCE = ~(-1L << SEQUENCE_BIT); /** * 每一部分向左的位移 */ private final static long MACHINE_LEFT = SEQUENCE_BIT; private final static long DATACENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT; private final static long TIMESTMP_LEFT = DATACENTER_LEFT + DATACENTER_BIT; private final long datacenterId; //数据中心 private final long machineId; //机器标识 private long sequence = 0L; //序列号 private long lastStmp = -1L;//上一次时间戳 public Snowflake(long datacenterId, long machineId) { if (datacenterId > MAX_DATACENTER_NUM || datacenterId < 0) { throw new IllegalArgumentException("数据中心的id不能小于0或者大于最大值" + MAX_DATACENTER_NUM); } if (machineId > MAX_MACHINE_NUM || machineId < 0) { throw new IllegalArgumentException("机器标识的id不能小于0或者大于最大值" + MAX_MACHINE_NUM); } this.datacenterId = datacenterId; this.machineId = machineId; } /** * 产生下一个ID * * @return id */ public synchronized long nextId() { long currStmp = System.currentTimeMillis(); if (currStmp < lastStmp) { throw new RuntimeException("时间改变,不能再次生成id"); } if (currStmp == lastStmp) { //相同毫秒内,序列号自增 sequence = (sequence + 1) & MAX_SEQUENCE; //同一毫秒的序列数已经达到最大 if (sequence == 0L) { currStmp = getNextMill(); } } else { //不同毫秒内,序列号置为0 sequence = 0L; } lastStmp = currStmp; return (currStmp - START_STMP) << TIMESTMP_LEFT //时间戳部分 | datacenterId << DATACENTER_LEFT //数据中心部分 | machineId << MACHINE_LEFT //机器标识部分 | sequence; //序列号部分 } /** * 获取下一毫秒 * * @return 。 */ private long getNextMill() { long mill = System.currentTimeMillis(); while (mill <= lastStmp) { mill = System.currentTimeMillis(); } return mill; } }
package org.xiaov.extra.id;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.xiaov.bean.Snowflake;
import org.xiaov.bean.date.DatePattern;

import java.util.Date;

/**
 * 

* 雪花算法生成id帮助类 *

* * @author xiaovcloud * @since 2021/7/8 16:42 */
@Component public class SnowflakeHelper { /** * 起始时间 */ private static final long START_STMP = DatePattern.START_STMP; /** * 机器码 */ private static long machineId; /** * 数据中心 */ private static long datacenterId; @Value("${id.snowflake.machineId:1}") public void setMachineId(long machine) { machineId = machine; } @Value("${id.snowflake.datacenterId:1}") public void setDatacenterId(long datacenter) { datacenterId = datacenter; } /** * 获取id * * @return id */ public static long nextId() { Snowflake snowflake = new Snowflake(datacenterId, machineId); return snowflake.nextId(); } /** * 根据雪花id 反推时间 * * @param id 雪花id * @return 时间 */ public static Date getDateById(long id) { long timeStamp = getTimestampById(id); return new Date(timeStamp); } /** * 根据雪花id 反推时间戳 * * @param id 雪花id * @return 时间戳 */ public static long getTimestampById(long id) { long timeStamp = id >> 22; timeStamp = timeStamp + START_STMP; return timeStamp; } }

你可能感兴趣的:(笔记,算法,java)