Twitter_Snowflake生成主键代码
来源:互联网 发布:如何提高淘宝店铺销量 编辑:程序博客网 时间:2024/06/01 18:37
package com.common.common;/** * Twitter_Snowflake<br> * SnowFlake的结构如下(每部分用-分开):<br> * 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - * 000000000000 <br> * 1位标识,由于long基本类型在Java中是带符号的,最高位是符号位,正数是0,负数是1,所以id一般是正数,最高位是0<br> * 41位时间截(毫秒级),注意,41位时间截不是存储当前时间的时间截,而是存储时间截的差值(当前时间截 - 开始时间截) * 得到的值),这里的的开始时间截,一般是我们的id生成器开始使用的时间 * ,由我们程序来指定的(如下下面程序IdWorker类的startTime属性)。41位的时间截,可以使用69年,年T = (1L << 41) / * (1000L * 60 * 60 * 24 * 365) = 69<br> * 10位的数据机器位,可以部署在1024个节点,包括5位datacenterId和5位workerId<br> * 12位序列,毫秒内的计数,12位的计数顺序号支持每个节点每毫秒(同一机器,同一时间截)产生4096个ID序号<br> * 加起来刚好64位,为一个Long型。<br> * SnowFlake的优点是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由数据中心ID和机器ID作区分),并且效率较高,经测试, * SnowFlake每秒能够产生26万ID左右。 */public class SnowflakeIdWorker { // ==============================Fields=========================================== /** 开始时间截 */ private final long twepoch = 629740800000L; /** 机器id所占的位数 */ private final long workerIdBits = 5L; /** 数据标识id所占的位数 */ private final long datacenterIdBits = 5L; /** 支持的最大机器id,结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数) */ private final long maxWorkerId = -1L ^ (-1L << workerIdBits); /** 支持的最大数据标识id,结果是31 */ private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits); /** 序列在id中占的位数 */ private final long sequenceBits = 12L; /** 机器ID向左移12位 */ private final long workerIdShift = sequenceBits; /** 数据标识id向左移17位(12+5) */ private final long datacenterIdShift = sequenceBits + workerIdBits; /** 时间截向左移22位(5+5+12) */ private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits; /** 生成序列的掩码,这里为1023 (0b1111111111=0x3ff=1023) */ private final long sequenceMask = -1L ^ (-1L << (sequenceBits - 2)); /** 工作机器ID(0~31) */ private long workerId; /** 数据中心ID(0~31) */ private long datacenterId; /** 毫秒内序列(0~4095) */ private long sequence = 0L; /** 上次生成ID的时间截 */ private long lastTimestamp = -1L; // ==============================Constructors===================================== /** * 构造函数 * * @param datacenterId * 数据中心ID (0~31) * @param workerId * 工作ID (0~31) */ public SnowflakeIdWorker(long datacenterId, long workerId) { if (workerId > maxWorkerId || workerId < 0) { throw new IllegalArgumentException(String.format( "worker Id can't be greater than %d or less than 0", maxWorkerId)); } if (datacenterId > maxDatacenterId || datacenterId < 0) { throw new IllegalArgumentException(String.format( "datacenter Id can't be greater than %d or less than 0", maxDatacenterId)); } this.workerId = workerId; this.datacenterId = datacenterId; } // ==============================Methods========================================== /** * 获得下一个ID (该方法是线程安全的) * * @return SnowflakeId */ public synchronized long nextId() { long timestamp = timeGen(); // 如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常 if (timestamp < lastTimestamp) { throw new RuntimeException( String.format( "Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp)); } // 如果是同一时间生成的,则进行毫秒内序列 if (lastTimestamp == timestamp) { sequence = (sequence + 1) & sequenceMask; // 毫秒内序列溢出 if (sequence == 0) { // 阻塞到下一个毫秒,获得新的时间戳 timestamp = tilNextMillis(lastTimestamp); } } // 时间戳改变,毫秒内序列重置 else { sequence = 0L; } // 上次生成ID的时间截 lastTimestamp = timestamp; // 移位并通过或运算拼到一起组成64位的ID return ((timestamp - twepoch) << timestampLeftShift) // | (datacenterId << datacenterIdShift) // | (workerId << workerIdShift) // | sequence; } /** * 阻塞到下一个毫秒,直到获得新的时间戳 * * @param lastTimestamp * 上次生成ID的时间截 * @return 当前时间戳 */ protected long tilNextMillis(long lastTimestamp) { long timestamp = timeGen(); while (timestamp <= lastTimestamp) { timestamp = timeGen(); } return timestamp; } /** * 返回以毫秒为单位的当前时间 * * @return 当前时间(毫秒) */ protected long timeGen() { return System.currentTimeMillis(); } // ==============================Test============================================= /** 测试 */ public static void main(String[] args) { SnowflakeIdWorker idWorker = new SnowflakeIdWorker(1, 1); System.out.println("Binary\tid"); for (int i = 0; i < 1000; i++) { long id = idWorker.nextId(); System.out.println(Long.toBinaryString(id) + "\t" + id); // System.out.println(id); } }}
/** * @File:IdGenerator.java **/package com.common.common;/** * @Description:ID * @author:rongshaolin * @date:2017-08-31 19:43 */public class IdGenerator { private static SnowflakeIdWorker snowflakeIdWorker; /** * 项目 */ private static Long project; /** * 节点 */ private static Long node; volatile private static IdGenerator instance = null; /** * @param pd 项目定义 project define (区分不同项目),从1开始到31 * @param id 节点ID,从1开始到31 */ public IdGenerator(Long pd, Long id) { if (pd > 31 || pd < 0) { throw new IllegalArgumentException(String.format("项目标识不能大于31")); } if (id > 31 || id < 0) { throw new IllegalArgumentException(String.format("节点数字不能大于31")); } if(this.node !=null && this.node >0){ throw new IllegalArgumentException(String.format("IdGenerator只初始化一次")); } this.node = id; snowflakeIdWorker = new SnowflakeIdWorker(pd, this.node); } /** * 获得一个唯一的ID * @return */ public static Long getId(){ return snowflakeIdWorker.nextId(); }// public static void main(String[] args) {//// Long node = IdGenerator.getNode();// System.out.println(node);//// new IdGenerator(31L);// node = IdGenerator.getNode();// System.out.println(node);//// new IdGenerator(30L);// node = IdGenerator.getNode();// System.out.println(node);//// new IdGenerator(29L);// node = IdGenerator.getNode();// System.out.println(node);//// }// public static void main(String[] args) {// System.out.println(-1L^(-1L<<10));// }}
阅读全文
0 0
- Twitter_Snowflake生成主键代码
- 生成主键
- oracle/mysql/sql_server对于主键生成策略的代码展示
- Mybatis generator 自动生成代码时 ,insert返回主键值
- SSH自动生成主键+UUID生成主键
- 数据主键生成方式
- 数据库主键生成策略
- Hibernate主键生成方式
- 数据库主键生成
- 数据库主键生成策略
- Hibernate 主键生成方式
- oralce主键自动生成
- hibernate主键生成策略
- 数据库主键生成策略
- hibernate主键生成方式
- Hibernate主键生成方式
- Hibernate 主键生成方式
- Hibernate 主键生成方式
- Java之Javassist对类的常用操作小结-yellowcong
- Spring Boot相关知识
- 下列代码之后的结果为()?
- REM手机屏幕适配
- jdbc连接数据库的7大步骤(以通过jdbc连接实现数据的插入、更新为例)
- Twitter_Snowflake生成主键代码
- EPON OLT网管系统的实现
- 破解 Navicat Premium 12
- NYOJ 303. 序号互换(数字/字符串处理+进制转换思想)
- UVA 1450 Airport (二分)PS:两种思路的改错,想AC就看我!!!
- 打开别人的vivado项目文件出错:Error when launching...Launcher time out.
- tomcat的启动方式
- git 命令使用
- C++学习笔记之对文件的操作