C#之Interlocked原子操作类

简介:

System.Threading.Interlocked 是 C# 中用于实现原子操作(Atomic Operations)的核心类。它提供了一组静态方法,确保在多线程环境下对共享变量的操作是线程安全的,且无需使用传统的锁机制(如 lock 或 Monitor),从而在高并发场景下具有更高的性能。

使用:

方法 描述 示例
Increment 原子地将指定变量加 1,并返回新值。 Interlocked.Increment(ref counter);
Decrement 原子地将指定变量减 1,并返回新值。 Interlocked.Decrement(ref counter);
Add 原子地将指定变量加上给定值,并返回新值。 Interlocked.Add(ref counter, 5);
Exchange 原子地将变量设置为新值,并返回原始值。 int old = Interlocked.Exchange(ref value, 10);
CompareExchange 比较并交换。如果当前值等于预期值,则替换为新值;否则不操作。始终返回原始值。 Interlocked.CompareExchange(ref value, newValue, expectedValue);

示例:

 private static int _counter = 0;

    static async Task Main(string[] args)
    {
        var tasks = new Task;
        
        // 启动10个线程,每个线程增加1000次
        for (int i = 0; i < 10; i++)
        {
            tasks[i] = Task.Run(() =>
            {
                for (int j = 0; j < 1000; j++)
                {
                    // 原子递增,保证最终结果一定是 10000
                    Interlocked.Increment(ref _counter);
                }
            });
        }

        await Task.WhenAll(tasks);
        Console.WriteLine($"Final Counter: {_counter}"); // 输出: Final Counter: 10000
    }

与传统lock区别:

维度 Interlocked lock (Monitor)
操作对象 单个基本类型变量 (int, long, reference) 任意代码块、对象、集合、多个变量
典型场景 计数器、状态标志位 (0/1)、CAS 无锁算法 保护集合 (List, Dictionary)、事务性业务逻辑、文件IO
性能 极高 (CPU 指令级,纳秒级) 中等 (涉及内核对象,微秒/毫秒级)
阻塞行为 不阻塞线程,失败即重试或返回 阻塞线程,直到获取锁
死锁风险 有 (若嵌套使用不当)

注意事项:

private static int counter = 0;
            Interlocked.Increment(ref counter); // 写入 1
            Interlocked.Decrement(ref counter); // 写入 0

            // 不要这么用:counter是一个普通的 int 字段,在多线程环境下读取不是原子的,不保证内存可见性
            if (counter > 0)
            {
                Debug.WriteLine("业务逻辑1");
            }
            else
            {
                Debug.WriteLine("业务逻辑2");
            }

            // 正确用法:永远使用 Interlocked 保证内存可见性
            if (Interlocked.CompareExchange(ref counter, 0, 0) > 0)
            {
                Debug.WriteLine("业务逻辑1");
            }
            else
            {
                Debug.WriteLine("业务逻辑2");
            }

拓展

锁(lock) 和信号量(Semaphore/SemaphoreSlim)区别:

  • 锁(lock):计数固定为 1。同一时刻,只有一个线程能进入被保护的代码块。其他线程必须排队等待。是线程相关的,它要求同一个线程必须负责释放锁(退出 lock 块)。

  • 信号量(Semaphore):计数可以设为 任意正整数(如 3)。它允许最多 N 个 线程同时进入,如果已有 N 个线程在占用,第 N+1 个线程就必须等待。是计数相关的。它不追踪线程 ID。任何一个线程都可以调用 Release() 来增加信号量的计数,即使这个线程之前并没有调用过 WaitOne()。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容