001/* 002 * Copyright 2024-2025, Warm-Flow (290631660@qq.com). 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.dromara.warm.flow.core.keygen; 017 018/** 019 * Twitter_Snowflake<br> 020 * SnowFlake的结构如下(每部分用-分开):<br> 021 * 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000 <br> 022 * 1位标识,由于long基本类型在Java中是带符号的,最高位是符号位,正数是0,负数是1,所以id一般是正数,最高位是0<br> 023 * 41位时间截(毫秒级),注意,41位时间截不是存储当前时间的时间截,而是存储时间截的差值(当前时间截 - 开始时间截) 024 * 得到的值),这里的的开始时间截,一般是我们的id生成器开始使用的时间,由我们程序来指定的(如下下面程序IdWorker类的startTime属性)。41位的时间截,可以使用69年,年T = (1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69<br> 025 * 10位的数据机器位,可以部署在1024个节点,包括5位datacenterId和5位workerId<br> 026 * 12位序列,毫秒内的计数,12位的计数顺序号支持每个节点每毫秒(同一机器,同一时间截)产生4096个ID序号<br> 027 * 加起来刚好64位,为一个Long型。<br> 028 * SnowFlake的优点是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由数据中心ID和机器ID作区分),并且效率较高,经测试,SnowFlake每秒能够产生26万ID左右。 029 * 030 * @author warm 031 */ 032public class SnowFlakeId19 implements KenGen{ 033 034 // ==============================Fields=========================================== 035 /** 036 * 开始时间截 (2015-01-01) 037 */ 038 private final long twepoch = 1420041600000L; 039 040 /** 041 * 机器id所占的位数 042 */ 043 private final long workerIdBits = 5L; 044 045 /** 046 * 数据标识id所占的位数 047 */ 048 private final long datacenterIdBits = 5L; 049 050 /** 051 * 支持的最大机器id,结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数) 052 */ 053 private final long maxWorkerId = -1L ^ (-1L << workerIdBits); 054 055 /** 056 * 支持的最大数据标识id,结果是31 057 */ 058 private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits); 059 060 /** 061 * 序列在id中占的位数 062 */ 063 private final long sequenceBits = 12L; 064 065 /** 066 * 机器ID向左移12位 067 */ 068 private final long workerIdShift = sequenceBits; 069 070 /** 071 * 数据标识id向左移17位(12+5) 072 */ 073 private final long datacenterIdShift = sequenceBits + workerIdBits; 074 075 /** 076 * 时间截向左移22位(5+5+12) 077 */ 078 private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits; 079 080 /** 081 * 生成序列的掩码,这里为4095 (0b111111111111=0xfff=4095) 082 */ 083 private final long sequenceMask = -1L ^ (-1L << sequenceBits); 084 085 /** 086 * 工作机器ID(0~31) 087 */ 088 private long workerId; 089 090 /** 091 * 数据中心ID(0~31) 092 */ 093 private long datacenterId; 094 095 /** 096 * 毫秒内序列(0~4095) 097 */ 098 private long sequence = 0L; 099 100 /** 101 * 上次生成ID的时间截 102 */ 103 private long lastTimestamp = -1L; 104 105 //==============================Constructors===================================== 106 107 /** 108 * 构造函数 109 * 110 * @param workerId 工作ID (0~31) 111 * @param datacenterId 数据中心ID (0~31) 112 */ 113 public SnowFlakeId19(long workerId, long datacenterId) { 114 if (workerId > maxWorkerId || workerId < 0) { 115 throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId)); 116 } 117 if (datacenterId > maxDatacenterId || datacenterId < 0) { 118 throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId)); 119 } 120 this.workerId = workerId; 121 this.datacenterId = datacenterId; 122 } 123 124 // ==============================Methods========================================== 125 126 /** 127 * 获得下一个ID (该方法是线程安全的) 128 * 129 * @return SnowflakeId 130 */ 131 @Override 132 public synchronized long nextId() { 133 long timestamp = timeGen(); 134 135 // 如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常 136 if (timestamp < lastTimestamp) { 137 throw new RuntimeException( 138 String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp)); 139 } 140 141 // 如果是同一时间生成的,则进行毫秒内序列 142 if (lastTimestamp == timestamp) { 143 sequence = (sequence + 1) & sequenceMask; 144 // 毫秒内序列溢出 145 if (sequence == 0) { 146 // 阻塞到下一个毫秒,获得新的时间戳 147 timestamp = tilNextMillis(lastTimestamp); 148 } 149 } 150 // 时间戳改变,毫秒内序列重置 151 else { 152 sequence = 0L; 153 } 154 155 // 上次生成ID的时间截 156 lastTimestamp = timestamp; 157 158 // 移位并通过或运算拼到一起组成64位的ID 159 return ((timestamp - twepoch) << timestampLeftShift) // 160 | (datacenterId << datacenterIdShift) // 161 | (workerId << workerIdShift) // 162 | sequence; 163 } 164 165 /** 166 * 阻塞到下一个毫秒,直到获得新的时间戳 167 * 168 * @param lastTimestamp 上次生成ID的时间截 169 * @return 当前时间戳 170 */ 171 protected long tilNextMillis(long lastTimestamp) { 172 long timestamp = timeGen(); 173 while (timestamp <= lastTimestamp) { 174 timestamp = timeGen(); 175 } 176 return timestamp; 177 } 178 179 /** 180 * 返回以毫秒为单位的当前时间 181 * 182 * @return 当前时间(毫秒) 183 */ 184 protected long timeGen() { 185 return System.currentTimeMillis(); 186 } 187}