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

多线程环境下计数器值未达预期,如何实现线程安全递增?

修复多线程下共享计数器的竞态条件问题

你的问题根源在于_counter++并非原子操作,它在CPU层面会拆分为三个独立步骤:读取当前_counter的值、对值执行加1运算、将新值写回_counter。当多个线程同时执行这些步骤时,会出现线程间的操作覆盖——比如线程A刚读取了_counter的当前值,线程B也读取了同一个值,两者各自加1后写回,最终两次递增只生效一次,导致计数丢失。

以下是两种可靠的修复方案:

方案一:使用Interlocked类的原子操作

Interlocked类提供了一系列原生支持的原子操作,能确保读取、修改、写入的整个过程不会被其他线程打断,是简单计数器场景下最优的选择。修改后的代码如下:

public class DataProcessor
{
    private static int _counter = 0;

    public async Task ProcessDataAsync()
    {
        var tasks = new List<Task>();

        for (int i = 0; i < 1000; i++)
        {
            tasks.Add(Task.Run(() => IncrementCounter()));
        }

        await Task.WhenAll(tasks);
    }

    private void IncrementCounter()
    {
        // 原子递增操作,确保线程安全
        Interlocked.Increment(ref _counter);
    }
}

方案二:使用lock语句加锁

如果后续需要对共享数据执行更复杂的多步操作,lock语句会更灵活。它通过互斥锁确保同一时间只有一个线程能执行锁块内的代码,避免竞态条件。修改后的代码如下:

public class DataProcessor
{
    private static int _counter = 0;
    // 声明静态只读的锁对象,确保所有线程共享同一锁,且不会被意外修改
    private static readonly object _lockObject = new object();

    public async Task ProcessDataAsync()
    {
        var tasks = new List<Task>();

        for (int i = 0; i < 1000; i++)
        {
            tasks.Add(Task.Run(() => IncrementCounter()));
        }

        await Task.WhenAll(tasks);
    }

    private void IncrementCounter()
    {
        lock (_lockObject)
        {
            _counter++;
        }
    }
}

两种方案对比

  • Interlocked:基于CPU原子指令实现,无线程阻塞开销,性能更高,适合简单的原子操作(如计数器增减)。
  • lock:基于.NET的Monitor类实现,会在锁被占用时阻塞线程,开销略高,但支持复杂的多步共享数据操作。

内容的提问来源于stack exchange,提问作者Vishal Kumar Gupta

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 12:30:57