博主喝口茶,一毛也是爱

收缩

C# 线程安全问题

224 人阅读
分类:

线程安全:如果你的代码在进程中有多个线程同时运行这一段,如果每次运行的结果都跟单线程运行时的结果一致,那么就是线程安全的

看下面代码

private static int iNum = 0;
private static int iAsync = 0;
public static void Operation()
{
    for (int i = 0; i < 10000; i++)
    {
        iNum++;
    }
    for (int i = 0; i < 10000; i++)
    {
        Task.Run(() =>
        {
            iAsync++;
        });
    }

    Console.WriteLine($"同步方法 iNum={iNum}");
    Console.WriteLine($"异步方法 iAsync={iAsync}");
}

iNum等于10000(这个毫无疑问)

iAsync会在0到10000之间的不确定值,这就导致了线程安全问题(创建多个线程并发操作会存在同时操作iAsync字段,最终只会导致一个成功处理,其他处理将会被忽略)

那么如何避免这个问题?

1. 使用Lock加锁

加锁代码

private static int iNum = 0;
private static int iAsync = 0;
private static readonly object objLock = new object();
public static void Operation()
{
    for (int i = 0; i < 10000; i++)
    {
        iNum++;
    }
    for (int i = 0; i < 10000; i++)
    {
        Task.Run(() =>
        {
            lock (objLock)
            {
                iAsync++;
            }
        });
    }

    Console.WriteLine($"同步方法 iNum={iNum}");
    Console.WriteLine($"异步方法 iAsync={iAsync}");
}

运行之后发现iNum和iAsync都等于10000

那么线程安全除了使用lock加锁之外还有什么方法?

2. 使用线程安全集合

System.Collections.Concurrent 下面的类都是线程安全的
  ConcurrentDictionary 表示可由多个线程同时访问的键/值对的线程安全集合
  ConcurrentQueue  表示线程安全的先进先出 (FIFO) 集合
  ConcurrentStack  表示线程安全的后进先出 (LIFO) 集合

3. 使用数据拆分方式,每个线程处理不同部分数据来保证多个线程不处理同一数据(适合有一定规律的数据)

  1W条数据 > 创建10个线程来处理,可以将1W条数据分成10组任务,每个线程单独处理一个任务,这就保证了线程之间的安全了

4. 将数据放Redis队列中,多线程从redis队列中取

  因为redis是单线程的,保证了线程的安全操作

和博主交个朋友吧
    发布篇幅
    • 文章总数:0
    • 原创:0
    • 转载:0
    • 译文:0
    文章分类
      文章存档
      阅读排行