C# 线程安全问题
2020-05-10 22:12
4933 人阅读
分类:
线程安全:如果你的代码在进程中有多个线程同时运行这一段,如果每次运行的结果都跟单线程运行时的结果一致,那么就是线程安全的
看下面代码
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是单线程的,保证了线程的安全操作
和博主交个朋友吧