基於Twitter的ID生成器演算法的全域性唯一ID生成器

基於Twitter的ID生成器演算法的全域性唯一ID生成器

實際的程式碼 貼出作為大家的參考:package net。study。framework。orm。id;import java。util。Random;import org。slf4j。Logger;import org。slf4j。LoggerFactory;import org。springframework。beans。factory。SmartInitializingSingleton;/** * 基於Twitter的ID生成器演算法的全域性唯一ID生成器 */public class TwitterLongIdGenerator implements IdGenerator, SmartInitializingSingleton { private static Logger logger = LoggerFactory。getLogger(TwitterLongIdGenerator。class); public static final String WORKER_ID_PROP = “study。worker。id”; public static final String DATACENTER_ID_PROP = “study。datacenter。id”; private long sequence = 0L; private long epoch = 30 * 365 * 24 * 3600000L; // 時間紀元 2000-01-01 00:00 00 private long workerIdBits = 5L; // 節點ID長度 private long datacenterIdBits = 5L; // 資料中心ID長度 private long maxWorkerId = -1L ^ (-1L << workerIdBits); // 最大支援機器節點數0~31,一共32個 private long maxDatacenterId = -1L ^ (-1L << datacenterIdBits); // 最大支援資料中心節點數0~31,一共32個 private long sequenceBits = 12L; // 序列號12位 private long workerIdShift = sequenceBits; // 機器節點左移12位 private long datacenterIdShift = sequenceBits + workerIdBits; // 資料中心節點左移17位 private long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits; // 時間毫秒數左移22位 private long sequenceMask = -1L ^ (-1L << sequenceBits); // 4095 private long incrementBits = 10L; // 預設自增10位 private long incrementMask = -1L ^ (-1L << incrementBits); // 1024,自增到1024時從0重新開始自增 private long lastTimestamp = -1L; private long workerId;// 支援機器節點數0~31,最多32個 private long datacenterId;// 支援資料中心節點數0~31,最多32個 /** * workerId和datacenterId從系統變數讀取,若沒有設定系統變數則隨機一個 */ public TwitterLongIdGenerator() { Random random = new Random(); int randomWorker = random。nextInt(Long。valueOf(maxWorkerId)。intValue()); String worker = System。getProperty(WORKER_ID_PROP, String。valueOf(randomWorker)); long workerId = Long。valueOf(worker); if (workerId > maxWorkerId || workerId < 0) { throw new IllegalArgumentException( String。format(“worker Id can‘t be greater than %d or less than 0”, maxWorkerId)); } int randomDatacenter = random。nextInt(Long。valueOf(maxDatacenterId)。intValue()); String datacenter = System。getProperty(DATACENTER_ID_PROP, String。valueOf(randomDatacenter)); long datacenterId = Long。valueOf(datacenter); 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; logger。info(“Init TwitterLongIdGenerator width workerId:{} datacenterId:{}”, workerId, datacenterId); } 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) { // sequence自增,因為sequence只有12bit,所以和sequenceMask相與一下,去掉高位 sequence = (sequence + 1) & sequenceMask; // 判斷是否溢位,也就是每毫秒內超過4095,當為4096時,與sequenceMask相與,sequence就等於0 if (sequence == 0) { timestamp = tilNextMillis(lastTimestamp); // 自旋等待到下一毫秒 } } else { // 如果和上次生成時間不同,自增sequence,到incrementMask(1024)時,sequence計數重新從0開始累加 sequence = (sequence + 1) & incrementMask; } lastTimestamp = timestamp; // 最後按照規則拼出ID。 // 000000000000000000000000000000000000000000 00000 00000 000000000000 // time datacenterId workerId sequence return ((timestamp - epoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | sequence; } /** * 保證同一毫秒內的序列號不會重複 * @param lastTimestamp * @return */ private long tilNextMillis(long lastTime) { long timestamp = timeGen(); while (timestamp <= lastTime) { timestamp = timeGen(); } return timestamp; } private long timeGen() { return System。currentTimeMillis(); } @Override public Long generate() { return nextId(); } @Override public void afterSingletonsInstantiated() { LongIdGenerator。setIdGeneratorInstance(this); }}