public class Snowflake
{
private const int RegionIdBits = 2;
private const int WorkerIdBits = 10;
private const int SequenceBits = 11;
private static readonly int MaxRegionId = (1 << RegionIdBits) - 1; // 3
private static readonly int MaxWorkerId = (1 << WorkerIdBits) - 1; // 1023
private static readonly long SequenceMask = (1L << SequenceBits) - 1; // 2047
private static readonly int WorkerIdShift = SequenceBits; // 11
private static readonly int RegionIdShift = SequenceBits + WorkerIdBits; // 21
private static readonly int TimestampLeftShift = SequenceBits + WorkerIdBits + RegionIdBits; // 23
private readonly long _twepoch = 1400000000000L;
private long _lastTimestamp = -1L;
private long _sequence = 0L;
private readonly int _workerId;
private readonly int _regionId;
private readonly Random _random = new Random();
private readonly object _lock = new object();
public Snowflake(int workerId, int regionId = 0)
{
if (workerId < 0 || workerId > MaxWorkerId)
throw new ArgumentException($"WorkerId must be between 0 and {MaxWorkerId}");
if (regionId < 0 || regionId > MaxRegionId)
throw new ArgumentException($"RegionId must be between 0 and {MaxRegionId}");
_workerId = workerId;
_regionId = regionId;
}
public long Generate(int? busId = null)
{
bool isPadding = busId.HasValue;
int paddingNum = isPadding ? busId.Value : _regionId;
lock (_lock)
{
long timestamp = GetTime();
if (timestamp < _lastTimestamp)
{
long diff = _lastTimestamp - timestamp;
throw new InvalidOperationException(
$"Clock moved backwards. Refusing to generate id for {diff} milliseconds.");
}
if (timestamp == _lastTimestamp)
{
_sequence = (_sequence + 1) & SequenceMask;
if (_sequence == 0) // 当前毫秒内 sequence 用尽,等待下一毫秒
{
timestamp = TailNextMillis(_lastTimestamp);
// 关键修复:进入新毫秒后,sequence 应重新随机化(避免恒为 0)
_sequence = (long)_random.Next(0, (int)SequenceMask + 1);
}
}
else
{
// 不同毫秒:随机初始化 sequence(范围 0~2047)
_sequence = (long)_random.Next(0, (int)SequenceMask + 1);
}
_lastTimestamp = timestamp;
return ((timestamp - _twepoch) << TimestampLeftShift)
| ((long)paddingNum << RegionIdShift)
| ((long)_workerId << WorkerIdShift)
| _sequence;
}
}
private long TailNextMillis(long lastTimestamp)
{
long timestamp = GetTime();
while (timestamp <= lastTimestamp)
{
timestamp = GetTime();
}
return timestamp;
}
private static long GetTime() => DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
}
// 全局单例建议(例如在 DI 中注册为 Singleton)
public static class SnowflakeSingleton
{
private static readonly Lazy<Snowflake> _instance = new Lazy<Snowflake>(() => new Snowflake(workerId: 0));
public static Snowflake Instance => _instance.Value;
}
for (int i = 0; i < 100; i++)
{
Console.WriteLine(SnowflakeSingleton.Instance.Generate());
}
Console.Read();