Twitter的SnowFlake算法,使用SnowFlake算法生成一个整数,然后转化为62进制变成一个短地址URL


/**
* Twitter的SnowFlake算法,使用SnowFlake算法生成一个整数,然后转化为62进制变成一个短地址URL
* @author @author beyond https://github.com/beyondfengyu/SnowFlake
* @author xuliugen
* @date 2018/04/23
*/
public class SnowFlakeShortUrl { /**
* 起始的时间戳
*/
private final static long START_TIMESTAMP = 1480166465631L; /**
* 每一部分占用的位数
*/
private final static long SEQUENCE_BIT = 12; //序列号占用的位数
private final static long MACHINE_BIT = 5; //机器标识占用的位数
private final static long DATA_CENTER_BIT = 5; //数据中心占用的位数 /**
* 每一部分的最大值
*/
private final static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BIT);
private final static long MAX_MACHINE_NUM = -1L ^ (-1L << MACHINE_BIT);
private final static long MAX_DATA_CENTER_NUM = -1L ^ (-1L << DATA_CENTER_BIT); /**
* 每一部分向左的位移
*/
private final static long MACHINE_LEFT = SEQUENCE_BIT;
private final static long DATA_CENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;
private final static long TIMESTAMP_LEFT = DATA_CENTER_LEFT + DATA_CENTER_BIT; private long dataCenterId; //数据中心
private long machineId; //机器标识
private long sequence = 0L; //序列号
private long lastTimeStamp = -1L; //上一次时间戳 /**
* 根据指定的数据中心ID和机器标志ID生成指定的序列号
* @param dataCenterId 数据中心ID
* @param machineId 机器标志ID
*/
public SnowFlakeShortUrl(long dataCenterId, long machineId) {
if (dataCenterId > MAX_DATA_CENTER_NUM || dataCenterId < 0) {
throw new IllegalArgumentException("DtaCenterId can't be greater than MAX_DATA_CENTER_NUM or less than 0!");
}
if (machineId > MAX_MACHINE_NUM || machineId < 0) {
throw new IllegalArgumentException("MachineId can't be greater than MAX_MACHINE_NUM or less than 0!");
}
this.dataCenterId = dataCenterId;
this.machineId = machineId;
} /**
* 产生下一个ID
* @return
*/
public synchronized long nextId() {
long currTimeStamp = getNewTimeStamp();
if (currTimeStamp < lastTimeStamp) {
throw new RuntimeException("Clock moved backwards. Refusing to generate id");
} if (currTimeStamp == lastTimeStamp) {
//相同毫秒内,序列号自增
sequence = (sequence + 1) & MAX_SEQUENCE;
//同一毫秒的序列数已经达到最大
if (sequence == 0L) {
currTimeStamp = getNextMill();
}
} else {
//不同毫秒内,序列号置为0
sequence = 0L;
} lastTimeStamp = currTimeStamp; return (currTimeStamp - START_TIMESTAMP) << TIMESTAMP_LEFT //时间戳部分
| dataCenterId << DATA_CENTER_LEFT //数据中心部分
| machineId << MACHINE_LEFT //机器标识部分
| sequence; //序列号部分
} private long getNextMill() {
long mill = getNewTimeStamp();
while (mill <= lastTimeStamp) {
mill = getNewTimeStamp();
}
return mill;
} private long getNewTimeStamp() {
return System.currentTimeMillis();
} public static void main(String[] args) {
SnowFlakeShortUrl snowFlake = new SnowFlakeShortUrl(2, 3); for (int i = 0; i < (1 << 4); i++) {
//10进制
Long id = snowFlake.nextId();
//62进制
String convertedNumStr = NumericConvertUtils.toOtherNumberSystem(id, 62); //10进制转化为62进制
System.out.println("10进制:" + id + " 62进制:" + convertedNumStr); //TODO 执行具体的存储操作,可以存放在Redis等中 //62进制转化为10进制
System.out.println("62进制:" + convertedNumStr + " 10进制:" + NumericConvertUtils.toDecimalNumber(convertedNumStr, 62));
System.out.println();
}
}
}

进制转换工具,最大支持十进制和62进制的转换


/**
* 进制转换工具,最大支持十进制和62进制的转换
* 1、将十进制的数字转换为指定进制的字符串;
* 2、将其它进制的数字(字符串形式)转换为十进制的数字
* @author xuliugen
* @date 2018/04/23
*/
public class NumericConvertUtils { /**
* 在进制表示中的字符集合,0-Z分别用于表示最大为62进制的符号表示
*/
private static final char[] digits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'}; /**
* 将十进制的数字转换为指定进制的字符串
* @param number 十进制的数字
* @param seed 指定的进制
* @return 指定进制的字符串
*/
public static String toOtherNumberSystem(long number, int seed) {
if (number < 0) {
number = ((long) 2 * 0x7fffffff) + number + 2;
}
char[] buf = new char[32];
int charPos = 32;
while ((number / seed) > 0) {
buf[--charPos] = digits[(int) (number % seed)];
number /= seed;
}
buf[--charPos] = digits[(int) (number % seed)];
return new String(buf, charPos, (32 - charPos));
} /**
* 将其它进制的数字(字符串形式)转换为十进制的数字
* @param number 其它进制的数字(字符串形式)
* @param seed 指定的进制,也就是参数str的原始进制
* @return 十进制的数字
*/
public static long toDecimalNumber(String number, int seed) {
char[] charBuf = number.toCharArray();
if (seed == 10) {
return Long.parseLong(number);
} long result = 0, base = 1; for (int i = charBuf.length - 1; i >= 0; i--) {
int index = 0;
for (int j = 0, length = digits.length; j < length; j++) {
//找到对应字符的下标,对应的下标才是具体的数值
if (digits[j] == charBuf[i]) {
index = j;
}
}
result += index * base;
base *= seed;
}
return result;
} public static void main(String[] args) {
System.out.println(toOtherNumberSystem(1857568745871168L, 64));
System.out.println(toDecimalNumber("6CnbJfBt0", 64));
System.out.println();
System.out.println(toOtherNumberSystem(185748383552778241L, 64));
System.out.println(toDecimalNumber("ajWiKPh301", 64));
}
}

Java工具类-基于SnowFlake的短地址生成器的更多相关文章

  1. Java 工具类 IpUtil - 获取本机所有 IP 地址,LocalHost 对应地址 IP

    Java 工具类 IpUtil - 获取本机所有 IP 地址,LocalHost 对应地址 IP IP 工具类 源代码: /** * <p> * * @author XiaoPengwei ...

  2. Java工具类——通过配置XML验证Map

    Java工具类--通过配置XML验证Map 背景 在JavaWeb项目中,接收前端过来的参数时通常是使用我们的实体类进行接收的.但是呢,我们不能去决定已经搭建好的框架是怎么样的,在我接触的框架中有一种 ...

  3. Java工具类—包装类

    Java工具类--包装类 我们都知道,JDK 其实给我们提供了很多很多 Java 开发者已经写好的现成的类,他们其实都可以理解成工具类,比如我们常见的集合类,日期相关的类,数学相关的类等等,有了这些工 ...

  4. Java工具类——数学相关的类

    Java工具类--数学相关的类 在上一篇文章中,我们系统学习了 Java 里面的包装类,那么这篇文章,我们就来学习一下Java提供好的类--数学相关的类. 一.数学类介绍 在最早期学习 Java 基础 ...

  5. Java工具类之:包装类

    Java工具类--包装类 我们都知道,JDK 其实给我们提供了很多很多 Java 开发者已经写好的现成的类,他们其实都可以理解成工具类,比如我们常见的集合类,日期相关的类,数学相关的类等等,有了这些工 ...

  6. java工具类系列 (四.SerializationUtils)

    java工具类系列 (四.SerializationUtils) SerializationUtils该类为序列化工具类,也是lang包下的工具,主要用于序列化操作 import java.io.Se ...

  7. 排名前 16 的 Java 工具类

    在Java中,工具类定义了一组公共方法,这篇文章将介绍Java中使用最频繁及最通用的Java工具类.以下工具类.方法按使用流行度排名,参考数据来源于Github上随机选取的5万个开源项目源码. 一. ...

  8. 排名前16的Java工具类

    原文:https://www.jianshu.com/p/9e937d178203 在Java中,工具类定义了一组公共方法,这篇文章将介绍Java中使用最频繁及最通用的Java工具类.以下工具类.方法 ...

  9. 第一章 Java工具类目录

    在这一系列博客中,主要是记录在实际开发中会常用的一些Java工具类,方便后续开发中使用. 以下的目录会随着后边具体工具类的添加而改变. 浮点数精确计算 第二章 Java浮点数精确计算 crc32将任意 ...

随机推荐

  1. 深入使用Vue + TS

    深入使用TS 支持 render jsx 写法 这里一共分两步 首先得先让 vue 支持 jsx 写法 再让 vue 中的 ts 支持 jsx 写法 让 vue 支持 jsx 按照官方做法,安装Bab ...

  2. Java 全栈知识体系 - 个人博客

    摘自:https://www.pdai.tech/ 著作权归https://www.pdai.tech所有. 链接:https://www.pdai.tech/ Java 全栈知识体系 包含: Jav ...

  3. Java-GC 垃圾收集器(HotSpot)

    垃圾收集器为垃圾收集算法的具体实现,是执行垃圾收集算法的,是守护线程. HotSpot 虚拟机采用分代收集(JVM 规范并未对堆区进行划分),将堆分为年轻代和老年代,垃圾收集器也按照这样区分.不过已有 ...

  4. vsftpd 配置上传失败553

    1查看ftp服务 ftp://ftpuser:123456@10.11.102.58:8023 2 getsebool -a | grep ftp 临时关闭 [root@xuegod63~]# get ...

  5. JS判定数据类型

    1.typeof                我们能够使用typeof判断变量的身份,判断字符串得到string,数字和NaN得到number,函数会得到function等,但是判断数组,对象和nu ...

  6. LC 966. Vowel Spellchecker

    Given a wordlist, we want to implement a spellchecker that converts a query word into a correct word ...

  7. JavaScript this的使用

    当作用域不同时,我们可以将this暂时性的保存下来. 例如: _this =  this.

  8. 最详细React Native环境配置及项目初始化(2018-10-14)

    注意配环境一定要全程使用稳定VPN工具,否则会浪费大量时间!!!相信我 一.截止到项目初始化之前也就是执行这条命令之前都按官网的方法就可以 https://reactnative.cn/docs/ge ...

  9. 使用Statement对象执行静态sql语句

    import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java ...

  10. Access denied for user XX

    解决方法:将pom.xml中的mysql-connector-java降低版本(直接去maven仓库复制:https://mvnrepository.com/),比如: <!-- https:/ ...