多线程环境生成唯一integer ID出现重复,求正确thread-safe实现方案
多线程场景下生成唯一整数ID的正确实现方案
现有代码重复问题根因
Interlocked.Increment本身是原子操作,线程安全没有问题,出现ID重复的核心原因是32位int类型溢出:int最大值为2147483647,自增到该值后下一次操作会溢出到int.MinValue(-2147483648),继续自增就会和之前生成过的正整数ID重复。
最优实现方案(推荐)
优先换用64位长整型long,其最大值为9223372036854775807,常规业务场景下几乎不可能溢出,无需额外处理即可保证唯一:
public partial class Form1 : Form { // 初始化ID种子,默认从0开始,第一次自增返回1 private static long _sharedId = 0; private static long GetNextUniqueId() { // Interlocked.Increment对long类型的自增也是原子操作,全平台线程安全 return Interlocked.Increment(ref _sharedId); } void SimulateBackTestRow1() { while (true) { long id = GetNextUniqueId(); // 业务逻辑 } } void SimulateBackTestRow2() { while (true) { long id = GetNextUniqueId(); // 业务逻辑 } } // 启动任务代码不变 Task modifyTaskOne = Task.Run(() => SimulateBackTestRow1()); Task modifyTaskTwo = Task.Run(() => SimulateBackTestRow2()); }
强制使用int类型的兼容实现
如果业务限制必须用int类型,需要增加溢出校验逻辑,避免回绕重复:
public partial class Form1 : Form { private static int _sharedId = 0; private static SpinLock _spinLock = new SpinLock(); private static int GetNextUniqueId() { bool lockTaken = false; try { _spinLock.Enter(ref lockTaken); if (_sharedId == int.MaxValue) { // 按需处理溢出:要么抛出异常终止生成,要么确认所有旧ID已失效后重置为0 throw new OverflowException("ID已超出int最大值范围,无法生成新唯一ID"); // 重置逻辑:_sharedId = 0; } return Interlocked.Increment(ref _sharedId); } finally { if (lockTaken) { _spinLock.Exit(); } } } }
注意事项
- 所有ID获取必须走统一的
GetNextUniqueId方法,禁止在其他地方直接修改_sharedId变量 - 排除溢出场景后如果仍出现ID重复,请排查业务代码是否存在ID复用、或多进程/多实例各自维护ID种子的情况
内容的提问来源于stack exchange,提问作者Ivan
相关产品推荐
相关产品推荐

