根據twitter的snowflake算法生成惟一ID

C#版本

複製代碼
/// <summary>
    /// 根據twitter的snowflake算法生成惟一ID
    /// snowflake算法 64 位
    /// 0---0000000000 0000000000 0000000000 0000000000 0 --- 00000 ---00000 ---000000000000
    /// 第一位爲未使用(實際上也可做爲long的符號位),接下來的41位爲毫秒級時間,而後5位datacenter標識位,5位機器ID(並不算標識符,實際是爲線程標識),而後12位該毫秒內的當前毫秒內的計數,加起來恰好64位,爲一個Long型。
    /// 其中datacenter標識位起始是機器位,機器ID實際上是線程標識,能夠同一一個10位來表示不一樣機器
    /// </summary>
    public class IdWorker
    {
        //機器ID
        private static long workerId = 1;
        private static long twepoch = 687888001020L; //惟一時間,這是一個避免重複的隨機量,自行設定不要大於當前時間戳
        private static long sequence = 0L;
        private static int workerIdBits = 4; //機器碼字節數。4個字節用來保存機器碼
        public static long maxWorkerId = -1L ^ -1L << workerIdBits; //最大機器ID
        private static int sequenceBits = 10; //計數器字節數,10個字節用來保存計數碼
        private static int workerIdShift = sequenceBits; //機器碼數據左移位數,就是後面計數器佔用的位數
        private static int timestampLeftShift = sequenceBits + workerIdBits; //時間戳左移動位數就是機器碼和計數器總字節數
        public static long sequenceMask = -1L ^ -1L << sequenceBits; //一微秒內能夠產生計數,若是達到該值則等到下一微妙在進行生成
        private long lastTimestamp = -1L;

        public long nextId()
        {
            lock (this)
            {
                long timestamp = timeGen();
                if (this.lastTimestamp == timestamp)
                { //同一微妙中生成ID
                    IdWorker.sequence = (IdWorker.sequence + 1) & IdWorker.sequenceMask; //用&運算計算該微秒內產生的計數是否已經到達上限
                    if (IdWorker.sequence == 0)
                    {
                        //一微妙內產生的ID計數已達上限,等待下一微妙
                        timestamp = tillNextMillis(this.lastTimestamp);
                    }
                }
                else
                { //不一樣微秒生成ID
                    IdWorker.sequence = 0; //計數清0
                }
                if (timestamp < lastTimestamp)
                { //若是當前時間戳比上一次生成ID時時間戳還小,拋出異常,由於不能保證如今生成的ID以前沒有生成過
                    throw new Exception(string.Format("Clock moved backwards.  Refusing to generate id for {0} milliseconds",
                        this.lastTimestamp - timestamp));
                }
                this.lastTimestamp = timestamp; //把當前時間戳保存爲最後生成ID的時間戳
                long nextId = (timestamp - twepoch << timestampLeftShift) | IdWorker.workerId << IdWorker.workerIdShift | IdWorker.sequence;
                return nextId;
            }
        }

        /// <summary>
        /// 獲取下一微秒時間戳
        /// </summary>
        /// <param name="lastTimestamp"></param>
        /// <returns></returns>
        private long tillNextMillis(long lastTimestamp)
        {
            long timestamp = timeGen();
            while (timestamp <= lastTimestamp)
            {
                timestamp = timeGen();
            }
            return timestamp;
        }

        /// <summary>
        /// 生成當前時間戳
        /// </summary>
        /// <returns></returns>
        private long timeGen()
        {
            return (long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds;
        }
    }
複製代碼

 

JAVA版本

 

複製代碼
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

public class IdWorker {

    protected static final Logger LOG = LoggerFactory.getLogger(IdWorker.class);

    private long workerId;
    private long datacenterId;
    private long sequence = 0L;

    private long twepoch = 1288834974657L;

    private long workerIdBits = 5L;
    private long datacenterIdBits = 5L;
    private long maxWorkerId = -1L ^ (-1L << workerIdBits);
    private long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
    private long sequenceBits = 12L;

    private long workerIdShift = sequenceBits;
    private long datacenterIdShift = sequenceBits + workerIdBits;
    private long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
    private long sequenceMask = -1L ^ (-1L << sequenceBits);

    private long lastTimestamp = -1L;

    public IdWorker(long workerId, long datacenterId) {
        // sanity check for 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;
        LOG.info(String.format("worker starting. timestamp left shift %d, datacenter id bits %d, worker id bits %d, sequence bits %d, workerid %d", timestampLeftShift, datacenterIdBits, workerIdBits, sequenceBits, workerId));
    }

    public synchronized long nextId() {
        long timestamp = timeGen();

        if (timestamp < lastTimestamp) {
            LOG.error(String.format("clock is moving backwards.  Rejecting requests until %d.", 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;
        }

        lastTimestamp = timestamp;

        return ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | sequence;
    }

    protected long tilNextMillis(long lastTimestamp) {
        long timestamp = timeGen();
        while (timestamp <= lastTimestamp) {
            timestamp = timeGen();
        }
        return timestamp;
    }

    protected long timeGen() {
        return System.currentTimeMillis();
    }


}
複製代碼
相關文章
相關標籤/搜索