public class SnowflakeIdWorkerGenerator {
? ? private static final SnowflakeIdWorker snowflakeIdWorker = new SnowflakeIdWorker();
? ? public static Long nextId() {
? ? ? ? return snowflakeIdWorker.nextId();
? ? }
? ? public static String nextStringId() {
? ? ? ? return String.valueOf(snowflakeIdWorker.nextId());
? ? }
? ? public static String createOrderNo() {
? ? ? ? return DateUtil.getDate("yyyyMMdd")+snowflakeIdWorker.nextId();
? ? }
//? ? public static void main(String[] args) {
//? ? ? ? System.out.println(DateUtil.getDate("yyyyMMdd")+snowflakeIdWorker.nextId());
//? ? }
}
import java.text.SimpleDateFormat;
import java.util.Date;
@SuppressWarnings("all")
public class SnowflakeIdWorker {
? ? // ============================== Constants===========================================
? ? private final static String ERROR_CLOCK_BACK = "時(shí)間回?fù)苁靥耄芙^為超出%d毫秒生成ID";
? ? private final static String ERROR_ATTR_LIMIT = "%s屬性的范圍為0-%d";
? ? private final static String MSG_UID_PARSE = "{\"UID\":\"%s\",\"timestamp\":\"%s\",\"workerId\":\"%d\",\"dataCenterId\":\"%d\",\"sequence\":\"%d\"}";
? ? private final static String DATE_PATTERN_DEFAULT = "yyyy-MM-dd HH:mm:ss";
? ? // ==============================Fields===========================================
? ? /** 開(kāi)始時(shí)間截 (2017-12-25)桐玻,用于用當(dāng)前時(shí)間戳減去這個(gè)時(shí)間戳,算出偏移量 */
? ? private final long twepoch = 1551582622686L;
? ? /** 機(jī)器id所占的位數(shù)(表示只允許workId的范圍為:0-1023) */
? ? private final long workerIdBits = 5L;
? ? /** 數(shù)據(jù)標(biāo)識(shí)id所占的位數(shù) */
? ? private final long datacenterIdBits = 5L;
? ? /** 支持的最大機(jī)器id,結(jié)果是31 (這個(gè)移位算法可以很快的計(jì)算出幾位二進(jìn)制數(shù)所能表示的最大十進(jìn)制數(shù)) */
? ? public final long maxWorkerId = -1L ^ (-1L << workerIdBits);
? ? /** 支持的最大數(shù)據(jù)標(biāo)識(shí)id巾表,結(jié)果是31 */
? ? private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
? ? /** 序列在id中占的位數(shù) (表示只允許sequenceId的范圍為:0-4095)*/
? ? private final long sequenceBits = 12L;
? ? /** 機(jī)器ID向左移12位 */
? ? private final long workerIdShift = sequenceBits;
? ? /** 數(shù)據(jù)標(biāo)識(shí)id向左移17位(12+5) */
? ? private final long datacenterIdShift = sequenceBits + workerIdBits;
? ? /** 時(shí)間截向左移22位(5+5+12) */
? ? private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
? ? /** 生成序列的掩碼,(防止溢出:位與運(yùn)算保證計(jì)算的結(jié)果范圍始終是 0-4095救崔,0b111111111111=0xfff=4095) */
? ? private final long sequenceMask = -1L ^ (-1L << sequenceBits);
? ? /** 工作機(jī)器ID(0~31) */
? ? private long workerId = 15;
? ? /** 數(shù)據(jù)中心ID(0~31) */
? ? private long datacenterId = 15;
? ? /** 毫秒內(nèi)序列(0~4095) */
? ? private long sequence = 0L;
? ? /** 上次生成ID的時(shí)間截 */
? ? private long lastTimestamp = -1L;
? ? private boolean isClock = false;
? ? public void setClock(boolean clock) {
? ? ? ? isClock = clock;
? ? }
? ? // ==============================Methods==========================================
/**
? ? * 獲得下一個(gè)ID (該方法是線程安全的)
*
? ? * @return SnowflakeId
*/
? ? public synchronized long nextId() {
? ? ? ? long timestamp = timeGen();
? ? ? ? // 閏秒:如果當(dāng)前時(shí)間小于上一次ID生成的時(shí)間戳锭部,說(shuō)明系統(tǒng)時(shí)鐘回退過(guò)這個(gè)時(shí)候應(yīng)當(dāng)拋出異常
? ? ? ? if (timestamp < lastTimestamp) {
? ? ? ? ? ? long offset = lastTimestamp - timestamp;
? ? ? ? ? ? if (offset <= 5) {
? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? // 時(shí)間偏差大小小于5ms,則等待兩倍時(shí)間
? ? ? ? ? ? ? ? ? ? wait(offset << 1);// wait
? ? ? ? ? ? ? ? ? ? timestamp = timeGen();
? ? ? ? ? ? ? ? ? ? if (timestamp < lastTimestamp) {
? ? ? ? ? ? ? ? ? ? ? ? // 還是小于篙顺,拋異常并上報(bào)
? ? ? ? ? ? ? ? ? ? ? ? throw new RuntimeException(String.format(ERROR_CLOCK_BACK, lastTimestamp - timestamp));
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? } catch (InterruptedException e) {
? ? ? ? ? ? ? ? ? ? throw new RuntimeException(e);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? throw new RuntimeException(String.format(ERROR_CLOCK_BACK, lastTimestamp - timestamp));
? ? ? ? ? ? }
}
? ? ? ? // 解決跨毫秒生成ID序列號(hào)始終為偶數(shù)的缺陷:如果是同一時(shí)間生成的偶芍,則進(jìn)行毫秒內(nèi)序列
? ? ? ? if (lastTimestamp == timestamp) {
? ? ? ? ? ? // 通過(guò)位與運(yùn)算保證計(jì)算的結(jié)果范圍始終是0-4095
? ? ? ? ? ? sequence = (sequence + 1) & sequenceMask;
? ? ? ? ? ? // 毫秒內(nèi)序列溢出
? ? ? ? ? ? if (sequence == 0) {
? ? ? ? ? ? ? ? // 阻塞到下一個(gè)毫秒,獲得新的時(shí)間戳
? ? ? ? ? ? ? ? timestamp = tilNextMillis(lastTimestamp);
? ? ? ? ? ? }
? ? ? ? } else {
? ? ? ? ? ? // 時(shí)間戳改變,毫秒內(nèi)序列重置
? ? ? ? ? ? sequence = 0L;
? ? ? ? }
? ? ? ? // 上次生成ID的時(shí)間截
? ? ? ? lastTimestamp = timestamp;
? ? ? ? /*
? ? ? ? * 1.左移運(yùn)算是為了將數(shù)值移動(dòng)到對(duì)應(yīng)的段(41德玫、5匪蟀、5,12那段因?yàn)楸緛?lái)就在最右宰僧,因此不用左移)
? ? ? ? * 2.然后對(duì)每個(gè)左移后的值(la材彪、lb、lc琴儿、sequence)做位或運(yùn)算段化,是為了把各個(gè)短的數(shù)據(jù)合并起來(lái),合并成一個(gè)二進(jìn)制數(shù)? ? ? ? * 3.最后轉(zhuǎn)換成10進(jìn)制造成,就是最終生成的id(64位的ID)
*/
? ? ? ? return ((timestamp - twepoch) << timestampLeftShift) //
? ? ? ? ? ? ? ? | (datacenterId << datacenterIdShift) //
? ? ? ? ? ? ? ? | (workerId << workerIdShift) //
? ? ? ? ? ? ? ? | sequence;
? ? }
? ? /**
? ? * @方法名稱 parseUID
? ? * @功能描述 <pre>反解析UID
*/
? ? public String parseUID(Long uid) {
? ? ? ? long totalBits = 64L;// 總位數(shù)
? ? ? ? long signBits = 1L;// 標(biāo)識(shí)
? ? ? ? long timestampBits = 41L;// 時(shí)間戳
? ? ? ? // 解析Uid:標(biāo)識(shí) -- 時(shí)間戳 -- 數(shù)據(jù)中心 -- 機(jī)器碼 --序列
? ? ? ? long sequence = (uid << (totalBits - sequenceBits)) >>> (totalBits - sequenceBits);
? ? ? ? long dataCenterId = (uid << (timestampBits + signBits)) >>> (totalBits - datacenterIdBits);
? ? ? ? long workerId = (uid << (timestampBits + signBits + datacenterIdBits)) >>> (totalBits - workerIdBits);
? ? ? ? long deltaSeconds = uid >>> (datacenterIdBits + workerIdBits + sequenceBits);
? ? ? ? // 時(shí)間處理(補(bǔ)上開(kāi)始時(shí)間戳)
? ? ? ? Date thatTime = new Date(twepoch + deltaSeconds);
? ? ? ? String date = new SimpleDateFormat(DATE_PATTERN_DEFAULT).format(thatTime);
? ? ? ? // 格式化輸出
? ? ? ? return String.format(MSG_UID_PARSE, uid, date, workerId, dataCenterId, sequence);
? ? }
? ? /**
? ? * @方法名稱 parseUID
? ? * @功能描述 <pre>反解析UID(字符串截取显熏,性能相對(duì)差;不推薦使用)
*/
? ? public String parseUID(String uid) {
? ? ? ? uid = Long.toBinaryString(Long.parseLong(uid));
? ? ? ? int len = uid.length();
? ? ? ? // 解析Uid:標(biāo)識(shí) -- 時(shí)間戳 -- 數(shù)據(jù)中心 -- 機(jī)器碼 --序列
? ? ? ? int sequenceStart = len < workerIdShift ? 0 : (int)(len - workerIdShift);// sequence起始數(shù)
? ? ? ? int workerStart = len < datacenterIdShift ? 0 : (int)(len - datacenterIdShift);// worker起始數(shù)
? ? ? ? int timeStart = len < timestampLeftShift ? 0 : (int)(len - timestampLeftShift);// 時(shí)間起始數(shù)
? ? ? ? String sequence = uid.substring(sequenceStart, len);
? ? ? ? String workerId = sequenceStart == 0 ? "0" : uid.substring(workerStart, sequenceStart);
? ? ? ? String dataCenterId = workerStart == 0 ? "0" : uid.substring(timeStart, workerStart);
? ? ? ? // 時(shí)間處理(補(bǔ)上開(kāi)始時(shí)間戳)
? ? ? ? String time = timeStart == 0 ? "0" : uid.substring(0, timeStart);
? ? ? ? Date timeDate = new Date(Long.parseLong(time, 2) + twepoch);
? ? ? ? String date = new SimpleDateFormat(DATE_PATTERN_DEFAULT).format(timeDate);
? ? ? ? // 格式化輸出
? ? ? ? return String.format(MSG_UID_PARSE, uid, date, Integer.valueOf(workerId, 2), Integer.valueOf(dataCenterId, 2), Integer.valueOf(sequence, 2));
? ? }
? ? /**
? ? * 保證返回的毫秒數(shù)在參數(shù)之后(阻塞到下一個(gè)毫秒晒屎,直到獲得新的時(shí)間戳)
*
? ? * @param lastTimestamp 上次生成ID的時(shí)間截
? ? * @return 當(dāng)前時(shí)間戳
? ? */
? ? protected long tilNextMillis(long lastTimestamp) {
? ? ? ? long timestamp = timeGen();
? ? ? ? while (timestamp <= lastTimestamp) {
? ? ? ? ? ? timestamp = timeGen();
? ? ? ? }
? ? ? ? return timestamp;
? ? }
? ? /**
? ? * 獲得系統(tǒng)當(dāng)前毫秒數(shù)
? ? *
? ? * @return 當(dāng)前時(shí)間(毫秒)
*/
? ? protected long timeGen() {
? ? ? ? if (isClock) {
? ? ? ? ? ? // 解決高并發(fā)下獲取時(shí)間戳的性能問(wèn)題
? ? ? ? ? ? return new Date().getTime();
? ? ? ? } else {
? ? ? ? ? ? return System.currentTimeMillis();
? ? ? ? }
}
}