namespace OSS.Tools.Num; /// /// 数字编号生成基类 /// public class BaseSnowNumGenerator { //【sequence 部分】 随机序列 private long _maxSequence; // 最大值 private int _sequenceBitLength; //长度 // 【WorkId部分】 工作Id private long _maxWorkerId; // 最大值 private int _workerIdBitLength; // 长度 /// /// workerId需要偏移的位置 /// protected int WorkerLeftShift { get; private set; } /// /// Timestamp 需要偏移的位置 /// protected int TimestampLeftShift { get; private set; } private void InitialConfig(int seqBitLength, int worIdBitLength) { _sequenceBitLength = seqBitLength; _maxSequence = -1L ^ (-1L << _sequenceBitLength); _workerIdBitLength = worIdBitLength; _maxWorkerId = -1L ^ (-1L << _workerIdBitLength); WorkerLeftShift = _sequenceBitLength; TimestampLeftShift = WorkerLeftShift + _workerIdBitLength; } /// /// 获取当前的工作ID /// public long WorkId { get; internal set; } private long _sequence; // 时间戳下 序号值 private long _timestamp; // 最后一次的时间戳值 private readonly object obj = new object(); // /// /// 构造函数 /// protected BaseSnowNumGenerator(int workId, int seqBitLength, int worIdBitLength) { InitialConfig(seqBitLength, worIdBitLength); if (workId > _maxWorkerId || workId < 0) { throw new ArgumentException("workId", $"工作Id不能大于 {_maxWorkerId} 或 小于 0"); } WorkId = workId; } /// /// 生成编号 /// /// public long NewNum() { long ts, seq; lock (obj) { SetTimestampAndSeq(); ts = _timestamp; seq = _sequence; } return CombineNum(ts, seq); } /// /// 组合数字ID /// /// /// /// private long CombineNum(long timestamp, long sequence) { return (timestamp << TimestampLeftShift) | (WorkId << WorkerLeftShift) | sequence; } private void SetTimestampAndSeq() { var newTimestamp = TimeMilliNum(); if (newTimestamp < _timestamp) { //如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常 throw new ArgumentException( $"当前时间小于上次生成时间 {_timestamp - newTimestamp} 毫秒,注意系统时间是否发生变化!"); } // 如果是同一时间生成的,则进行毫秒内序列 if (_timestamp == newTimestamp) { _sequence = (_sequence + 1) & _maxSequence; //毫秒内序列溢出 //阻塞到下一个毫秒,获得新的时间戳 if (_sequence == 0) newTimestamp = WaitNextMillis(_timestamp); } //时间戳改变,毫秒内序列重置 else _sequence = 0L; _timestamp = newTimestamp; } /// /// 当前毫秒内序列使用完,等待下一毫秒 /// /// protected long WaitNextMillis(long curTimeSpan) { long timeTicks; do { timeTicks = TimeMilliNum(); } while (timeTicks <= curTimeSpan); return timeTicks; } private static readonly long _timeStartTicks = new DateTime(2020, 1, 1).ToUniversalTime().Ticks; /// /// 时间戳数字编号(精度 毫秒 /// /// private static long TimeMilliNum() { return (DateTime.UtcNow.Ticks - _timeStartTicks) / 10000; } }