You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#中类似Interlocked.Increment的线程安全可回收序列计数器问询

线程安全可复用顺序计数器实现

嘿,刚好碰到过类似的需求!C#标准库并没有内置完全匹配你描述的组件——也就是那种既能按顺序生成新序号,又能回收已用序号并优先复用(放回队列顶端就优先拿)的线程安全计数器。不过咱们基于.NET自带的并发工具,很快就能实现一个符合要求的版本。

核心思路

  • 用你熟悉的Interlocked.Increment来保证新序号的线程安全生成,确保多线程下不会出现重复的新序号;
  • 用ConcurrentStack<long>存储回收的序号——因为你要求归还的序号放回队列顶端,下次优先获取,栈的后进先出特性正好完美匹配这个逻辑;
  • 每次拿序号时,先尝试从栈里取回收的,没有的话再生成新的。

完整代码实现

using System.Collections.Concurrent;

public class ReusableSequentialCounter
{
    // 记录下一个要生成的新序号初始值
    private long _nextNewId = 0;
    // 存储回收的序号,线程安全栈
    private readonly ConcurrentStack<long> _recycledIds = new ConcurrentStack<long>();

    public long GetNextId()
    {
        // 先尝试复用回收的序号,栈顶的先拿
        if (_recycledIds.TryPop(out long recycledId))
        {
            return recycledId;
        }
        // 没有回收的就生成新序号,减1是让第一个序号从0开始,和你示例一致
        return Interlocked.Increment(ref _nextNewId) - 1;
    }

    public void ReturnId(long id)
    {
        // 把归还的序号压入栈顶,下次获取时会优先拿到它
        _recycledIds.Push(id);
    }
}

验证你的示例场景

咱们来跑一遍你说的流程:

  1. 连续调用GetNextId(),会依次拿到0,1,2,3,4,5;
  2. 调用ReturnId(4),再调用ReturnId(1)——此时栈里的顺序是[1,4](因为Push是往栈顶加,所以后Push的1在最上面);
  3. 再次调用GetNextId(),会先拿到1,再拿4,之后再调用就会生成6,7...,完全和你预期的一致!

线程安全说明

  • ConcurrentStack本身就是为并发场景设计的,TryPop和Push都是线程安全的原子操作,不需要额外加锁;
  • Interlocked.Increment是系统级的原子操作,保证多线程下新序号不会重复;
  • 整个实现没有显式锁,性能表现也不错,适合高并发的场景。

如果有特殊需求(比如要限制回收序号的范围、或者需要持久化回收的序号),还可以在这个基础上轻松扩展~

内容的提问来源于stack exchange,提问作者tval

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 09:10:05