自己写雪花算法IdWorker
- package com.aiyusheng.shopping.util;
- import java.lang.management.ManagementFactory;
- import java.net.InetAddress;
- import java.net.NetworkInterface;
- import java.text.SimpleDateFormat;
- import java.util.Date;
- /**
- * <p>名称:IdWorker.java</p>
- * <p>描述:分布式自增长ID</p>
- * <pre>
- * Twitter的 Snowflake JAVA实现方案
- * </pre>
- * 核心代码为其IdWorker这个类实现,其原理结构如下,我分别用一个0表示一位,用—分割开部分的作用:
- * 1||0---0000000000 0000000000 0000000000 0000000000 0 --- 00000 ---00000 ---000000000000
- * 在上面的字符串中,第一位为未使用(实际上也可作为long的符号位),接下来的41位为毫秒级时间,
- * 然后5位datacenter标识位,5位机器ID(并不算标识符,实际是为线程标识),
- * 然后12位该毫秒内的当前毫秒内的计数,加起来刚好64位,为一个Long型。
- * 这样的好处是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由datacenter和机器ID作区分),
- * 并且效率较高,经测试,snowflake每秒能够产生26万ID左右,完全满足需要。
- * <p>
- * 64位ID (42(毫秒)+5(机器ID)+5(业务编码)+12(重复累加))
- *
- * @author Polim
- */
- public class IdWorker {
- // 时间起始标记点,作为基准,一般取系统的最近时间(一旦确定不能变动)
- private final static long TWEPOCH= 1288834974657L;
- // 机器标识位数
- private final static long WORKDER_ID_BITS = 5L;
- // 数据中心标识位数
- private final static long DATACENTER_ID_BITS = 5L;
- // 机器ID最大值
- private final static long MAX_WORKDER_ID= -1L ^ (-1L << WORKDER_ID_BITS);
- // 数据中心ID最大值
- private final static long MAX_DATACENTER_ID= -1L ^ (-1L << DATACENTER_ID_BITS);
- // 毫秒内自增位
- private final static long SEQUENCE_BITS= 12L;
- // 机器ID偏左移12位
- private final static long WORKDER_ID_SHIFT= SEQUENCE_BITS;
- // 数据中心ID左移17位
- private final static long DATACENTER_ID_SHIFT= SEQUENCE_BITS + WORKDER_ID_BITS;
- // 时间毫秒左移22位
- private final static long TIMESTAMP_LEFT_SHIFT = SEQUENCE_BITS + WORKDER_ID_BITS + SEQUENCE_BITS;
- private final static long SEQUENCE_MASK= -1L ^ (-1L << SEQUENCE_BITS);
- /* 上次生产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(MAX_DATACENTER_ID);
- this.workerId = getMaxWorkerId(datacenterId, MAX_WORKDER_ID);
- }
- /**
- * @param workerId
- * 工作机器ID
- * @param datacenterId
- * 序列号
- */
- public IdWorker(long workerId, long datacenterId) {
- if (workerId > MAX_WORKDER_ID || workerId < 0) {
- throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", MAX_WORKDER_ID));
- }
- if (datacenterId > MAX_WORKDER_ID || datacenterId < 0) {
- throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", MAX_DATACENTER_ID));
- }
- this.workerId = workerId;
- this.datacenterId = datacenterId;
- }
- /**
- * 获取下一个ID
- *
- * @return
- */
- public synchronized long nextId() {
- 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) & SEQUENCE_MASK;
- if (sequence == 0) {
- // 当前毫秒内计数满了,则等待下一秒
- timestamp = tilNextMillis(lastTimestamp);
- }
- } else {
- sequence = 0L;
- }
- lastTimestamp = timestamp;
- // ID偏移组合生成最终的ID,并返回ID
- long nextId = ((timestamp - TWEPOCH) << TIMESTAMP_LEFT_SHIFT)
- | (datacenterId << DATACENTER_ID_SHIFT)
- | (workerId << WORKDER_ID_SHIFT) | sequence;
- return nextId;
- }
- /**
- * 功能描述: 自动补全生成32位
- * @Param:
- * @Return: java.lang.String
- * @Author: chenzhian
- * @Date: 2020/12/2 17:24
- * @Description:
- */
- public synchronized String next32Id(){
- String Id= nextId()+"";
- String nowtime = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
- Integer surplusLength=32-Id.length()-nowtime.length();
- if(surplusLength>0){
- //自动补缺数字
- String strsurplus = String.format("%0"+surplusLength+"d", 0);
- return nowtime+strsurplus+Id;
- }else if(surplusLength==0){
- return nowtime+Id;
- }else{
- return nowtime.substring(0,(nowtime.length()+surplusLength))+Id;
- }
- }
- /**
- * 阻塞到下一个毫秒,直到获得新的时间戳
- * @param lastTimestamp 上次生成ID的时间截
- * @return 当前时间戳
- */
- private long tilNextMillis(final long lastTimestamp) {
- long timestamp = this.timeGen();
- while (timestamp <= lastTimestamp) {
- timestamp = this.timeGen();
- }
- return timestamp;
- }
- /**
- * 返回以毫秒为单位的当前时间
- * @return 当前时间(毫秒)
- */
- 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;
- }
- }
- package com.aiyusheng.shopping.config;
- import org.springframework.boot.context.properties.ConfigurationProperties;
- @ConfigurationProperties(prefix = "ly.worker")
- public class IdWorkerProperties {
- private long workerId;// 当前机器id
- private long datacenterId;// 序列号
- public long getWorkerId() {
- return workerId;
- }
- public void setWorkerId(long workerId) {
- this.workerId = workerId;
- }
- public long getDatacenterId() {
- return datacenterId;
- }
- public void setDatacenterId(long datacenterId) {
- this.datacenterId = datacenterId;
- }
- }
- package com.aiyusheng.shopping.config;
- import com.aiyusheng.shopping.util.IdWorker;
- import org.springframework.boot.context.properties.EnableConfigurationProperties;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- @Configuration
- @EnableConfigurationProperties(IdWorkerProperties.class)
- public class IdWorkerConfig {
- @Bean
- public IdWorker idWorker(IdWorkerProperties prop) {
- return new IdWorker(prop.getWorkerId(), prop.getDatacenterId());
- }
- }
配置文件application.properties
- ly.worker.workerId=1
- ly.worker.datacenterId=1
自己写雪花算法IdWorker的更多相关文章
- 分布式id生成器,雪花算法IdWorker
/** * <p>名称:IdWorker.java</p> * <p>描述:分布式自增长ID</p> * <pre> * Twitter的 ...
- 分布式id的生成方式——雪花算法
雪花算法是twitter开源的一个算法. 由64位0或1组成,其中41位是时间戳,10位工作机器id,12位序列号,该类通过方法nextID()实现id的生成,用Long数据类型去存储. 我们使用id ...
- 【Java】分布式自增ID算法---雪花算法 (snowflake,Java版)
一般情况,实现全局唯一ID,有三种方案,分别是通过中间件方式.UUID.雪花算法. 方案一,通过中间件方式,可以是把数据库或者redis缓存作为媒介,从中间件获取ID.这种呢,优点是可以体现全局的递增 ...
- 分布式雪花算法获取id
实现全局唯一ID 一.采用主键自增 最常见的方式.利用数据库,全数据库唯一. 优点: 1)简单,代码方便,性能可以接受. 2)数字ID天然排序,对分页或者需要排序的结果很有帮助. 缺点: 1)不同数据 ...
- 雪花算法(SnowFlake)Java实现
分布式id生成算法的有很多种,Twitter的SnowFlake就是其中经典的一种. 算法原理 SnowFlake算法生成id的结果是一个64bit大小的整数,它的结构如下图: 1bit,不用,因为二 ...
- ID 生成器 雪花算法
https://blog.csdn.net/wangming520liwei/article/details/80843248 ID 生成器 雪花算法 2018年06月28日 14:58:43 wan ...
- 分布式系统-主键唯一id,订单编号生成-雪花算法-SnowFlake
分布式系统下 我们每台设备(分布式系统-独立的应用空间-或者docker环境) * SnowFlake的优点是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由数据中心ID和机器ID作 ...
- 分布式Snowflake雪花算法
前言 项目中主键ID生成方式比较多,但是哪种方式更能提高的我们的工作效率.项目质量.代码实用性以及健壮性呢,下面作了一下比较,目前雪花算法的优点还是很明显的. 优缺点比较 UUID(缺点:太长.没法排 ...
- 一个类似 Twitter 雪花算法 的 连续序号 ID 产生器 SeqIDGenerator
项目地址 : https://github.com/kelin-xycs/SeqIDGenerator 今天 QQ 群 里有网友问起产生唯一 ID 的方法 有哪些, 讨论了各种方法 . 有网 ...
随机推荐
- python学习番外篇——字符串的数据类型转换及内置方法
目录 字符串的数据类型转换及内置方法 类型转换 内置方法 优先掌握的方法 需要掌握的方法 strip, lstrip, rstrip lower, upper, islower, isupper 插入 ...
- BUUCTF-Web:[GXYCTF2019]Ping Ping Ping
题目 解题过程 1.题目页面提示?ip=,猜测是让我们把这个当做变量上传参数,由此猜想是命令注入 2.用管道符加上linux常用命令ls(windwos可以尝试dir)试试 所谓管道符(linux)的 ...
- OA办公软件篇(三)—审批流
背景 作用 迭代历程 具体实现 写在最后 背景 在前面两篇文章中,我们分别讲了组织架构和权限管理,今天我们来讲一个跟组织架构关系比较密切的功能-审批流. 审批流,通俗来说就是一个完整的审批流程,是 ...
- Golang(go语言)开发环境配置
VSCode开发环境配置 目录 VSCode开发环境配置 先到VSCode官网去下载适合自己系统的VSCode安装软件 演示在WIndows下 安装使用 演示在Linux(Ubuntu/centos) ...
- NLP教程(7) - 问答系统
作者:韩信子@ShowMeAI 教程地址:http://www.showmeai.tech/tutorials/36 本文地址:http://www.showmeai.tech/article-det ...
- 用js给闺女做了一个加减乘除的html
下班回家用二十分钟给闺女做了一个加减乘除的页面,顺便记录下代码,时间仓促,后期再来修改吧 目录结构 -yq --menu.html --yq.html --yq50.html --yq70.html ...
- 基于 Jenkins + Kubernetes + Argo CD 的完整 DevOps 流程记录(1) - 环境部署
一.环境准备 1.1 镜像仓库 整套 DevOps 流程使用 Harbor 作为内部镜像仓库,所有构建产物(镜像)都会推送到 Harbor,以备后续进行项目部署.Harbor 从 2.x 版本开始支持 ...
- Vue 中 watch 的一个坑
开发所用 Vue 版本 2.6.11 子组件 coma 中两个属性: props: { url: { type: String, default: '' }, oriurl:{ type: Strin ...
- 构建第一个模型:KNN算法(Iris_dataset)
利用鸢尾花数据集完成一个简单的机器学习应用~万丈高楼平地起,虽然很基础,但是还是跟着书敲了一遍代码. 一.模型构建流程 1.获取数据 本次实验的Iris数据集来自skicit-learn的datase ...
- ConfigurationManager姿势快闪
C# ConfigurationManager使用记录 最近一个祖传代码是使用.NET Fx写就的,我在使用控制台程序获取配置时有些折腾. 下面记录一些管理配置文件的姿势: Configuration ...