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 * warm 生成14位有序id 020 * 021 * @author warm 022 */ 023public class SnowFlakeId14 implements KenGen { 024 /** 025 * 开始时间截 (本次时间戳为:Thu Nov 04 2010 09:42:54 GMT+0800 (中国标准时间)----1288834974657L---1656543015264587776--19 ) 026 */ 027 private final long startTime = 1683803335498L; 028 029 /** 030 * 机器id所占的位数 031 */ 032 private final long workerIdBits = 3L; 033 034 /** 035 * 支持的最大机器id,结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数) 036 */ 037 private final long maxWorkerId = -1L ^ (-1L << workerIdBits); 038 039 /** 040 * 序列在id中占的位数 041 */ 042 private final long sequenceBits = 5L; 043 044 /** 045 * 机器ID向左移12位 046 */ 047 private final long workerIdShift = sequenceBits; 048 049 /** 050 * 时间截向左移22位(10+12) 051 */ 052 private final long timestampLeftShift = sequenceBits + workerIdBits; 053 054 /** 055 * 生成序列的掩码,这里为4095 (0b111111111111=0xfff=4095) 056 */ 057 private final long sequenceMask = -1L ^ (-1L << sequenceBits); 058 059 /** 060 * 工作机器ID(0~1024) 061 */ 062 private long workerId; 063 064 /** 065 * 毫秒内序列(0~4095) 066 */ 067 private long sequence = 0L; 068 069 /** 070 * 上次生成ID的时间截 071 */ 072 private long lastTimestamp = -1L; 073 074 //==============================Constructors===================================== 075 076 /** 077 * 构造函数 078 * 079 * @param workerId 工作ID (0~1024) 080 */ 081 public SnowFlakeId14(long workerId) { 082 if (workerId > maxWorkerId || workerId < 0) { 083 throw new IllegalArgumentException(String.format("workerId can't be greater than %d or less than 0", maxWorkerId)); 084 } 085 this.workerId = workerId; 086 } 087 088 // ==============================Methods========================================== 089 090 /** 091 * 获得下一个ID (该方法是线程安全的) 092 * 093 * @return SnowflakeId 094 */ 095 @Override 096 public synchronized long nextId() { 097 long timestamp = timeGen(); 098 099 //如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常 100 if (timestamp < lastTimestamp) { 101 throw new RuntimeException( 102 String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp)); 103 } 104 105 //如果是同一时间生成的,则进行毫秒内序列 106 if (lastTimestamp == timestamp) { 107 sequence = (sequence + 1) & sequenceMask; 108 //毫秒内序列溢出 109 if (sequence == 0) { 110 //阻塞到下一个毫秒,获得新的时间戳 111 timestamp = tilNextMillis(lastTimestamp); 112 } 113 } 114 //时间戳改变,毫秒内序列重置 115 else { 116 sequence = 0L; 117 } 118 119 //上次生成ID的时间截 120 lastTimestamp = timestamp; 121 122 //移位并通过或运算拼到一起组成64位的ID 123 return ((timestamp - startTime) << timestampLeftShift) 124 | (workerId << workerIdShift) 125 | sequence; 126 } 127 128 /** 129 * 阻塞到下一个毫秒,直到获得新的时间戳 130 * 131 * @param lastTimestamp 上次生成ID的时间截 132 * @return 当前时间戳 133 */ 134 protected long tilNextMillis(long lastTimestamp) { 135 long timestamp = timeGen(); 136 while (timestamp <= lastTimestamp) { 137 timestamp = timeGen(); 138 } 139 return timestamp; 140 } 141 142 /** 143 * 返回以毫秒为单位的当前时间 144 * 145 * @return 当前时间(毫秒) 146 */ 147 protected long timeGen() { 148 return System.currentTimeMillis(); 149 } 150 151}