using System.Reflection.PortableExecutable; namespace ApiDemo { /// /// 雪花算法生成id /// public class SnowFlake { /// /// 机器id所占的位数 /// private const int workerIdBits = 5; /// /// 数据表述id所占位数 /// private const int datacenterIdBits = 5; /// /// 支持的最大机器id,结果是31 /// private const long maxWorkerId = -1L ^ (-1L << workerIdBits); /// /// 支持的最大数据表示id,结果是31 /// private const long maxDatacenterId = -1L ^ (-1L << datacenterIdBits); /// /// 序列在id中所占的位数 /// private const int sequenceBits = 12; /// /// 数据标识id向左移17位 /// private const int datacenterIdShift = sequenceBits + workerIdBits; /// /// 机器ID向左移12位 /// private const int workerIdShift = sequenceBits; private const int timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits; /// /// 生成序列的掩码 /// private const long sequenceMask = -1L ^ (-1L << sequenceBits); /// /// 数据中心ID(0-31) /// public long DatacenterId { get; private set; } /// /// 工作机器ID(0-31) /// public long WorkerId { get; private set; } /// /// 毫秒内序列(0-4095) /// public long Sequence { get; private set; } /// /// 上次生成ID的时间戳 /// public long LastTimestamp { get; private set; } /// /// 开始时间戳。首次使用前设置,否则无效,默认2010-1-1 /// public DateTime StartTimestamp { get; set; } = new DateTime(2010,1,1); static object syncRoot = new object(); static readonly Lazy snowflake = new(() => new SnowFlake(0L,0L)); /// /// 默认金泰实例,WorkerId = 0,DatacenterId = 0 /// public static SnowFlake Instance { get; } = snowflake.Value; /// /// 构造函数 /// /// 工作机器ID /// 数据中心ID /// public SnowFlake(long workerId,long datacenterId) { if (workerId > maxWorkerId || workerId < 0) { throw new ArgumentOutOfRangeException(nameof(workerId),$"不能大于{maxWorkerId}或小于0"); } if (datacenterId > maxDatacenterId || datacenterId < 0) { throw new ArgumentOutOfRangeException(nameof(datacenterId), $"不能大于{maxDatacenterId}或小于0"); } WorkerId = workerId; DatacenterId = datacenterId; Sequence = 0L; LastTimestamp = -1L; } /// /// 获取下一个ID /// /// public long NextId() { lock (syncRoot) { //获取当前时间戳 long timestamp = GetCurrentTimestamp(); if (timestamp > LastTimestamp)//时间戳改变,毫秒内序列重置 { Sequence = 0L; } else if (timestamp == LastTimestamp)//如果是同一时间生成的,则进行毫秒内序列 { Sequence = (Sequence + 1) & sequenceMask; if (Sequence == 0)//毫秒内序列溢出 { timestamp = GetNextTimestamp(LastTimestamp);//阻塞到下一个毫秒,获取新的时间戳 } } else//当前时间小于上一次ID生成的时间戳,证明系统时钟被回拨,此时需要做回拨处理 { Sequence = (Sequence + 1) & sequenceMask; if (Sequence > 0) { timestamp = LastTimestamp;//停留再最后一次时间戳上,等待系统时间追上后即完全度过了时钟回拨问题 } else { timestamp = LastTimestamp + 1;//直接进位到下一个毫秒 } } LastTimestamp = timestamp;//上次生成ID的时间戳 //移动并通过或运算拼到一起组成64位的ID var id = (timestamp << timestampLeftShift) | (DatacenterId << datacenterIdShift) | (WorkerId << workerIdShift) | Sequence; return id; } } /// /// 阻塞到下一个毫秒,直到获得新的时间戳 /// /// /// private long GetNextTimestamp(long lastTimestamp) { //获取当前时间戳 long timestamp = GetCurrentTimestamp(); while (timestamp <= lastTimestamp) { timestamp = GetCurrentTimestamp(); } return timestamp; } /// /// 获取当前时间戳 /// /// private long GetCurrentTimestamp() { return (long)(DateTime.Now - StartTimestamp).TotalMilliseconds; } } }