你是否在多线程开发中遇到过这样的问题:明明做了100万次计数,结果却少了几千个? 或者为了保证线程安全而使用了太多lock,导致程序性能大幅下降?
在高并发场景下,传统的锁机制往往成为性能瓶颈,而竞态条件又让程序行为变得不可预测。今天我们来深入探讨.NET中的Interlocked类——一个被低估但极其强大的无锁线程安全解决方案。
掌握Interlocked,让你的多线程程序既安全又高效!
在多线程环境中,当多个线程同时访问共享变量时,就会出现竞态条件:
C#// 危险的计数器实现
public class UnsafeCounter
{
private static int _counter = 0;
public static void Increment()
{
// 这里存在竞态条件!
_counter++; // 读取->增加->写回
}
}
问题所在:_counter++看似简单,实际包含读取、增加、写回三个步骤,多线程同时执行时会相互覆盖。
使用lock虽然能解决线程安全问题,但也带来了额外开销:
C#// 性能较差的同步方案
public class LockedCounter
{
private static int _counter = 0;
private static readonly object _lock = new object();
public static void Increment()
{
lock (_lock) // 每次都要获取锁,性能开销大
{
_counter++;
}
}
}
使用Interlocked实现线程安全的计数器,性能比lock方案快数倍:
C#namespace AppThreadSafeCounter
{
public class ThreadSafeCounter
{
private static volatile int _counter = 0;
private static readonly object _lockObject = new object();
#region 基本操作
public static int Increment()
{
return Interlocked.Increment(ref _counter);
}
public static int Decrement()
{
return Interlocked.Decrement(ref _counter);
}
public static int Add(int value)
{
return Interlocked.Add(ref _counter, value);
}
public static int Subtract(int value)
{
return Interlocked.Add(ref _counter, -value);
}
public static int GetValue()
{
return Interlocked.CompareExchange(ref _counter, 0, 0);
}
#endregion
#region 高级操作
public static int SetValue(int newValue)
{
return Interlocked.Exchange(ref _counter, newValue);
}
public static int CompareAndSwap(int expectedValue, int newValue)
{
return Interlocked.CompareExchange(ref _counter, newValue, expectedValue);
}
public static int Reset()
{
return Interlocked.Exchange(ref _counter, 0);
}
public static int IncrementIf(Func<int, bool> condition, int increment = 1)
{
if (condition == null)
throw new ArgumentNullException(nameof(condition));
int currentValue, newValue;
do
{
currentValue = _counter;
if (!condition(currentValue))
return currentValue;
newValue = currentValue + increment;
}
while (Interlocked.CompareExchange(ref _counter, newValue, currentValue) != currentValue);
return newValue;
}
public static int IncrementWithLimit(int maxValue, int increment = 1)
{
return IncrementIf(current => current + increment <= maxValue, increment);
}
public static int DecrementWithLimit(int minValue, int decrement = 1)
{
return IncrementIf(current => current - decrement >= minValue, -decrement);
}
#endregion
#region 统计和监控
public static CounterSnapshot GetSnapshot()
{
return new CounterSnapshot(GetValue(), DateTime.UtcNow);
}
public static bool IsZero()
{
return GetValue() == 0;
}
public static bool IsPositive()
{
return GetValue() > 0;
}
public static bool IsNegative()
{
return GetValue() < 0;
}
#endregion
#region 重载运算符
public static implicit operator int(ThreadSafeCounter counter)
{
return GetValue();
}
public override string ToString()
{
return GetValue().ToString();
}
#endregion
}
public readonly struct CounterSnapshot
{
public int Value { get; }
public DateTime Timestamp { get; }
public CounterSnapshot(int value, DateTime timestamp)
{
Value = value;
Timestamp = timestamp;
}
public override string ToString()
{
return $"Value: {Value}, Timestamp: {Timestamp:yyyy-MM-dd HH:mm:ss.fff} UTC";
}
}
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine("=== ThreadSafeCounter 示例 ===");
// 基本操作
Console.WriteLine($"初始值: {ThreadSafeCounter.GetValue()}");
Console.WriteLine($"增加后: {ThreadSafeCounter.Increment()}");
Console.WriteLine($"批量增加5: {ThreadSafeCounter.Add(5)}");
Console.WriteLine($"减少后: {ThreadSafeCounter.Decrement()}");
Console.WriteLine($"批量减少3: {ThreadSafeCounter.Subtract(3)}");
// 高级操作
int oldValue = ThreadSafeCounter.SetValue(100);
Console.WriteLine($"设置为100,旧值: {oldValue}");
// 条件操作
int result = ThreadSafeCounter.IncrementWithLimit(105, 3);
Console.WriteLine($"限制增加到105,结果: {result}");
result = ThreadSafeCounter.IncrementWithLimit(105, 10);
Console.WriteLine($"尝试超出限制增加,结果: {result}");
// 获取快照
var snapshot = ThreadSafeCounter.GetSnapshot();
Console.WriteLine($"快照: {snapshot}");
// 重置
oldValue = ThreadSafeCounter.Reset();
Console.WriteLine($"重置,旧值: {oldValue},新值: {ThreadSafeCounter.GetValue()}");
Console.WriteLine("=== 多线程测试 ===");
TestConcurrency();
}
private static void TestConcurrency()
{
const int threadCount = 10;
const int operationsPerThread = 1000;
ThreadSafeCounter.Reset();
var threads = new Thread[threadCount];
// 创建多个线程同时操作计数器
for (int i = 0; i < threadCount; i++)
{
threads[i] = new Thread(() =>
{
for (int j = 0; j < operationsPerThread; j++)
{
if (j % 2 == 0)
ThreadSafeCounter.Increment();
else
ThreadSafeCounter.Decrement();
}
});
}
// 启动所有线程
foreach (var thread in threads)
thread.Start();
// 等待所有线程完成
foreach (var thread in threads)
thread.Join();
Console.WriteLine($"多线程测试完成,最终值: {ThreadSafeCounter.GetValue()}");
Console.WriteLine($"期望值: 0 (每个线程执行相同数量的增加和减少操作)");
}
}
}

应用场景: 网站访问统计、并发用户数监控、性能指标收集
核心优势:
用整数模拟布尔标志,实现线程安全的状态切换:
C#namespace AppThreadSafeFlag
{
public class ThreadSafeFlag
{
// 0表示false,1表示true
private static int _isRunning = 0;
// 尝试启动(仅当未运行时)
public static bool TryStart()
{
// CAS操作:仅当值为0时设为1
return Interlocked.CompareExchange(ref _isRunning, 1, 0) == 0;
}
// 停止运行
public static void Stop()
{
Interlocked.Exchange(ref _isRunning, 0);
}
// 检查状态
public static bool IsRunning => _isRunning == 1;
}
internal class Program
{
static void Main(string[] args)
{
if (ThreadSafeFlag.TryStart())
{
Console.WriteLine("成功获得执行权限");
// 执行业务逻辑
ThreadSafeFlag.Stop();
}
else
{
Console.WriteLine("其他线程正在执行,跳过");
}
}
}
}
应用场景: 服务开关控制、资源可用性标记、一次性初始化标志
实现单例模式或延迟加载的高性能方案:
C#using System.Collections.Concurrent;
using System.Diagnostics;
namespace AppThreadSafeLazyInitialization
{
public class ThreadSafeLazyInitialization
{
private static object _instance;
private static int _initialized = 0; // 0=未初始化, 1=正在初始化, 2=已完成
public static object GetInstance()
{
// 快速路径:已经初始化完成
if (_instance != null)
return _instance;
// 尝试获得初始化权限
if (Interlocked.CompareExchange(ref _initialized, 1, 0) == 0)
{
try
{
// 只有一个线程能执行这里
_instance = CreateExpensiveObject();
Console.WriteLine($"对象初始化完成 - 线程ID: {Thread.CurrentThread.ManagedThreadId}");
}
finally
{
// 标记初始化完成
Interlocked.Exchange(ref _initialized, 2);
}
}
else
{
// 等待其他线程完成初始化
while (_initialized < 2)
{
Thread.Sleep(1); // 短暂等待
}
}
return _instance;
}
// 重置方法,用于测试
public static void Reset()
{
_instance = null;
_initialized = 0;
}
private static object CreateExpensiveObject()
{
Console.WriteLine($"开始创建对象 - 线程ID: {Thread.CurrentThread.ManagedThreadId}");
Thread.Sleep(100); // 模拟昂贵的初始化过程
return new { Data = "Expensive Object", CreatedAt = DateTime.Now, ThreadId = Thread.CurrentThread.ManagedThreadId };
}
}
internal class Program
{
static void Main(string[] args)
{
Console.OutputEncoding= System.Text.Encoding.UTF8;
Console.WriteLine("📋 单线程基本功能");
ThreadSafeLazyInitialization.Reset();
var instance1 = ThreadSafeLazyInitialization.GetInstance();
var instance2 = ThreadSafeLazyInitialization.GetInstance();
Console.WriteLine($"实例1和实例2是否相同: {ReferenceEquals(instance1, instance2)}");
Console.WriteLine($"实例详情: {instance1}");
Console.WriteLine();
}
}
}
应用场景: 单例模式、配置加载、数据库连接初始化
使用Interlocked实现自旋锁,避免线程阻塞:
C#using System.Diagnostics;
namespace AppNonBlockingLock
{
public class NonBlockingLock
{
private static int _lockState = 0; // 0=未锁定, 1=已锁定
public static bool TryAcquire()
{
return Interlocked.CompareExchange(ref _lockState, 1, 0) == 0;
}
public static void Release()
{
Interlocked.Exchange(ref _lockState, 0);
}
// 带超时的获取锁
public static bool TryAcquire(int timeoutMs)
{
var stopwatch = Stopwatch.StartNew();
while (stopwatch.ElapsedMilliseconds < timeoutMs)
{
if (TryAcquire())
return true;
Thread.SpinWait(10); // 短暂自旋
}
return false;
}
}
internal class Program
{
static void Main(string[] args)
{
if (NonBlockingLock.TryAcquire(1000)) // 1秒超时
{
try
{
// 执行需要同步的代码
Console.WriteLine("获得锁,执行关键操作");
}
finally
{
NonBlockingLock.Release();
}
}
}
}
}
应用场景: 短期资源保护、高频访问的临界区
安全地更新对象引用,常用于缓存更新场景:
C#using System;
using System.IO;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
namespace AppAtomicCache
{
// 配置类示例
public class AppConfig
{
public string DatabaseConnectionString { get; set; } = "";
public int MaxConnections { get; set; } = 100;
public string ApiEndpoint { get; set; } = "";
public bool EnableLogging { get; set; } = true;
public TimeSpan CacheTimeout { get; set; } = TimeSpan.FromMinutes(30);
public override string ToString()
{
return $"DB: {DatabaseConnectionString}, MaxConn: {MaxConnections}, API: {ApiEndpoint}, Logging: {EnableLogging}";
}
}
public class AtomicCache<T> where T : class
{
private static T _cachedData;
public static T GetOrUpdate(Func<T> factory)
{
var current = _cachedData;
if (current != null)
return current;
// 创建新数据
var newData = factory();
// 原子性地更新缓存(如果还是null的话)
var previous = Interlocked.CompareExchange(ref _cachedData, newData, null);
// 返回实际存储的值(可能是其他线程设置的)
return previous ?? newData;
}
public static void Update(T newData)
{
Interlocked.Exchange(ref _cachedData, newData);
}
public static void Clear()
{
Interlocked.Exchange(ref _cachedData, null);
}
public static bool HasValue => _cachedData != null;
}
internal class Program
{
private static readonly string ConfigFilePath = "appsettings.json";
static async Task Main(string[] args)
{
Console.WriteLine("=== 原子缓存示例 ===\n");
// 创建示例配置文件
await CreateSampleConfigFile();
// 演示基本用法
await DemoBasicUsage();
// 演示多线程安全性
await DemoThreadSafety();
// 演示缓存更新
await DemoCacheUpdate();
Console.WriteLine("\n按任意键退出...");
Console.ReadKey();
}
private static async Task CreateSampleConfigFile()
{
if (!File.Exists(ConfigFilePath))
{
var sampleConfig = new AppConfig
{
DatabaseConnectionString = "Server=localhost;Database=MyApp;Trusted_Connection=true;",
MaxConnections = 50,
ApiEndpoint = "https://api.example.com",
EnableLogging = true,
CacheTimeout = TimeSpan.FromMinutes(15)
};
var json = JsonSerializer.Serialize(sampleConfig, new JsonSerializerOptions { WriteIndented = true });
await File.WriteAllTextAsync(ConfigFilePath, json);
Console.WriteLine($"创建示例配置文件: {ConfigFilePath}");
}
}
private static async Task DemoBasicUsage()
{
Console.WriteLine("1. 基本用法演示:");
// 第一次调用 - 会加载配置
var config1 = AtomicCache<AppConfig>.GetOrUpdate(() =>
{
Console.WriteLine(" -> 首次加载配置文件...");
return LoadConfigFromFile();
});
Console.WriteLine($" 配置1: {config1}");
// 第二次调用 - 直接从缓存返回
var config2 = AtomicCache<AppConfig>.GetOrUpdate(() =>
{
Console.WriteLine(" -> 这句不应该被打印(因为有缓存)");
return LoadConfigFromFile();
});
Console.WriteLine($" 配置2: {config2}");
Console.WriteLine($" 两个实例是同一个对象: {ReferenceEquals(config1, config2)}\n");
await Task.Delay(100);
}
private static async Task DemoThreadSafety()
{
Console.WriteLine("2. 多线程安全性演示:");
// 清空缓存
AtomicCache<AppConfig>.Clear();
var loadCount = 0;
var tasks = new Task[10];
// 启动10个并发任务
for (int i = 0; i < tasks.Length; i++)
{
int taskId = i;
tasks[i] = Task.Run(() =>
{
var config = AtomicCache<AppConfig>.GetOrUpdate(() =>
{
Interlocked.Increment(ref loadCount);
Console.WriteLine($" -> 线程 {taskId} 正在加载配置...");
Thread.Sleep(100); // 模拟I/O延迟
return LoadConfigFromFile();
});
Console.WriteLine($" 线程 {taskId} 获得配置: {config.MaxConnections}");
return config;
});
}
await Task.WhenAll(tasks);
Console.WriteLine($" 实际加载次数: {loadCount} (理想情况应该是1)\n");
}
private static async Task DemoCacheUpdate()
{
Console.WriteLine("3. 缓存更新演示:");
var originalConfig = AtomicCache<AppConfig>.GetOrUpdate(() => LoadConfigFromFile());
Console.WriteLine($" 原始配置: MaxConnections = {originalConfig.MaxConnections}");
// 更新缓存
var newConfig = new AppConfig
{
DatabaseConnectionString = "Server=newserver;Database=MyApp;Trusted_Connection=true;",
MaxConnections = 200,
ApiEndpoint = "https://api.ottheach.cn",
EnableLogging = false,
CacheTimeout = TimeSpan.FromHours(1)
};
AtomicCache<AppConfig>.Update(newConfig);
Console.WriteLine(" -> 缓存已更新");
var updatedConfig = AtomicCache<AppConfig>.GetOrUpdate(() =>
{
Console.WriteLine(" -> 这句不应该被打印(缓存已存在)");
return LoadConfigFromFile();
});
Console.WriteLine($" 更新后配置: MaxConnections = {updatedConfig.MaxConnections}");
Console.WriteLine($" 是新配置对象: {ReferenceEquals(updatedConfig, newConfig)}");
await Task.Delay(100);
}
private static AppConfig LoadConfigFromFile()
{
try
{
// 模拟文件I/O延迟
Thread.Sleep(50);
if (File.Exists(ConfigFilePath))
{
var json = File.ReadAllText(ConfigFilePath);
var config = JsonSerializer.Deserialize<AppConfig>(json);
Console.WriteLine(" 配置文件加载成功");
return config ?? new AppConfig();
}
else
{
Console.WriteLine(" 配置文件不存在,使用默认配置");
return new AppConfig();
}
}
catch (Exception ex)
{
Console.WriteLine($" 加载配置失败: {ex.Message},使用默认配置");
return new AppConfig();
}
}
}
}

C#// ❌ 错误:嵌套使用Interlocked
public void BadPractice()
{
int value = 0;
// 这样会导致非预期结果
Interlocked.Add(ref value, Interlocked.Increment(ref _counter));
}
// ✅ 正确:分步使用
public void GoodPractice()
{
int value = 0;
int newCount = Interlocked.Increment(ref _counter);
Interlocked.Add(ref value, newCount);
}
| 场景类型 | 适用性 | 推荐方案 |
|---|---|---|
| 简单计数器 | ⭐⭐⭐⭐⭐ | Interlocked.Increment |
| 状态标志 | ⭐⭐⭐⭐⭐ | CompareExchange |
| 惰性初始化 | ⭐⭐⭐⭐ | CompareExchange + Exchange |
| 缓存更新 | ⭐⭐⭐⭐ | Exchange |
| 复杂数据结构 | ⭐⭐ | ConcurrentQueue等 |
| 长时间锁定 | ⭐ | Monitor、ReaderWriterLock |
通过本文的深入解析,我们掌握了Interlocked这个多线程编程神器的精髓。
三个核心要点回顾:
在高并发时代,掌握Interlocked不仅能让你的程序更安全,更能让你的代码更高效。它是每个C#开发者都应该掌握的核心技能。
现在就去尝试将你项目中的lock替换为Interlocked吧! 相信你会对性能提升感到惊喜。
💬 互动讨论:
觉得这篇文章对你有帮助?请转发给更多需要的同行,让我们一起写出更高质量的C#代码!
#C#开发 #多线程编程 #性能优化 #编程技巧 #Interlocked #线程安全
本文作者:技术老小子
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!