以下是 C# 中使用 int
类型结合 Interlocked
类实现原子操作的完整示例,涵盖状态切换、计数控制等常见场景:
完整代码示例csharp
using System;
using System.Threading;
/// <summary>
/// 基于整数类型的原子操作工具类(线程安全)
/// 适用于开关状态控制、计数器等场景
/// </summary>
public static class AtomicStateManager
{
// 核心状态变量:用整数表示不同状态
// 示例场景:0=关闭(False),1=开启(True);也可扩展为多状态(如0=未初始化,1=运行中,2=已停止)
private static int _state = 0;
#region 基础状态控制(开关场景)
/// <summary>
/// 原子设置状态为“开启”(对应值1)
/// </summary>
public static void Enable()
{
// 直接将状态设为1,无视当前值(原子操作)
Interlocked.Exchange(ref _state, 1);
}
/// <summary>
/// 原子设置状态为“关闭”(对应值0)
/// </summary>
public static void Disable()
{
// 直接将状态设为0,无视当前值(原子操作)
Interlocked.Exchange(ref _state, 0);
}
/// <summary>
/// 原子切换状态(0→1 或 1→0)
/// </summary>
public static void Toggle()
{
// 循环尝试切换,直到成功(处理并发冲突)
do
{
int currentState = _state; // 读取当前状态
int newState = currentState == 1 ? 0 : 1; // 计算目标状态
// 比较并交换:如果当前值仍为currentState,则更新为newState
// 若交换失败(返回值≠currentState),则重试
} while (Interlocked.CompareExchange(ref _state, newState, _state) != _state);
}
/// <summary>
/// 原子读取当前状态是否为“开启”
/// </summary>
/// <returns>True=开启(1),False=关闭(0)</returns>
public static bool IsEnabled()
{
// 用CompareExchange确保读取到最新值(避免CPU缓存导致的脏读)
return Interlocked.CompareExchange(ref _state, 0, 0) == 1;
}
#endregion
#region 计数器场景(原子增减)
/// <summary>
/// 原子递增状态值(+1)
/// </summary>
/// <returns>递增后的新值</returns>
public static int Increment()
{
return Interlocked.Increment(ref _state);
}
/// <summary>
/// 原子递减状态值(-1)
/// </summary>
/// <returns>递减后的新值</returns>
public static int Decrement()
{
return Interlocked.Decrement(ref _state);
}
/// <summary>
/// 原子读取当前计数值
/// </summary>
/// <returns>当前状态值</returns>
public static int GetCount()
{
return Interlocked.CompareExchange(ref _state, 0, 0);
}
#endregion
#region 高级场景:条件更新(仅当满足条件时修改)
/// <summary>
/// 仅当当前状态为“关闭”时,原子设置为“开启”
/// </summary>
/// <returns>True=更新成功,False=当前状态不满足条件</returns>
public static bool EnableIfDisabled()
{
// 比较并交换:若当前值为0(关闭),则更新为1(开启)
int originalValue = Interlocked.CompareExchange(ref _state, 1, 0);
return originalValue == 0; // 若原始值为0,说明更新成功
}
/// <summary>
/// 仅当当前状态为目标值时,原子更新为新值
/// </summary>
/// <param name="expectedValue">预期当前值</param>
/// <param name="newValue">目标新值</param>
/// <returns>True=更新成功,False=当前值不符预期</returns>
public static bool UpdateIfMatch(int expectedValue, int newValue)
{
int originalValue = Interlocked.CompareExchange(ref _state, newValue, expectedValue);
return originalValue == expectedValue;
}
#endregion
}
使用示例csharp
class Program
{
static void Main()
{
// 1. 开关状态场景
AtomicStateManager.Enable();
Console.WriteLine($"是否开启:{AtomicStateManager.IsEnabled()}"); // 输出:True
AtomicStateManager.Toggle();
Console.WriteLine($"切换后是否开启:{AtomicStateManager.IsEnabled()}"); // 输出:False
bool updateSuccess = AtomicStateManager.EnableIfDisabled();
Console.WriteLine($"是否成功开启:{updateSuccess}"); // 输出:True
Console.WriteLine($"当前状态:{AtomicStateManager.IsEnabled()}"); // 输出:True
// 2. 计数器场景
AtomicStateManager.Increment(); // 状态从1→2
AtomicStateManager.Increment(); // 状态从2→3
Console.WriteLine($"当前计数:{AtomicStateManager.GetCount()}"); // 输出:3
AtomicStateManager.Decrement(); // 状态从3→2
Console.WriteLine($"递减后计数:{AtomicStateManager.GetCount()}"); // 输出:2
// 3. 条件更新场景
bool conditionUpdate = AtomicStateManager.UpdateIfMatch(2, 100);
Console.WriteLine($"条件更新是否成功:{conditionUpdate}"); // 输出:True
Console.WriteLine($"更新后的值:{AtomicStateManager.GetCount()}"); // 输出:100
}
}
核心原理与优势
原子性保证:
Interlocked
类的方法通过底层硬件指令实现原子操作,确保操作过程不会被其他线程打断,避免竞态条件。性能优化:
相比lock
等锁机制,Interlocked
操作无需上下文切换,开销更小,适合高频访问场景。可见性保证:
所有Interlocked
操作会强制刷新 CPU 缓存,确保所有线程看到的是最新值,避免因缓存导致的数据不一致。灵活性扩展:
示例中用0
和1
表示开关状态,实际可扩展为多状态(如0=未初始化
、1=运行中
、2=已停止
),通过UpdateIfMatch
方法实现复杂状态转换。
这种方式特别适合 IIS 等多线程环境下的全局变量控制,可有效避免并发修改导致的异常。
VB.NET的用法例子:
将布尔值转换为整数类型(如 Integer
)后使用 Interlocked
类的原子操作(如递增、递减、比较交换),在多线程场景中会更直观且高效。这种方式特别适合需要 "开关状态切换" 或 "计数控制" 的场景。
以下是 VB.NET 中基于整数类型的原子操作实现,以 GetServerInfo
的状态控制为例:
实现示例:VB.NET 用整数类型模拟状态,结合原子操作
vb
Imports System.Threading
' 用整数表示状态:0=关闭(False),1=开启(True)
Private Shared _serverInfoState As Integer = 0 ' 初始状态:关闭
' 原子开启(设置为1)
Public Sub EnableServerInfo()
Interlocked.Exchange(_serverInfoState, 1)
End Sub
' 原子关闭(设置为0)
Public Sub DisableServerInfo()
Interlocked.Exchange(_serverInfoState, 0)
End Sub
' 原子切换状态(0→1 或 1→0)
Public Sub ToggleServerInfo()
' 循环尝试切换,直到成功(处理并发冲突)
Do
Dim currentState = _serverInfoState
Dim newState = If(currentState = 1, 0, 1)
' 比较并交换:如果当前值仍为 currentState,则更新为 newState
Loop While Interlocked.CompareExchange(_serverInfoState, newState, currentState) <> currentState
End Sub
' 原子读取当前状态
Public Function IsServerInfoEnabled() As Boolean
' 读取操作本身是原子的,但用 CompareExchange 确保可见性
Return Interlocked.CompareExchange(_serverInfoState, 0, 0) = 1
End Function
' 原子递增(适合计数场景)
Public Sub IncrementCounter()
Interlocked.Increment(_serverInfoState)
End Sub
' 原子递减(适合计数场景)
Public Sub DecrementCounter()
Interlocked.Decrement(_serverInfoState)
End Sub
优势说明
操作直观:
用0
和1
对应False
和True
,通过Interlocked.Increment
/Decrement
可直接实现计数,无需额外转换逻辑。性能优异:
Interlocked
类的方法是底层硬件支持的原子操作,比SyncLock
等锁机制开销更小,尤其适合高频访问的场景。避免竞态条件:
Exchange
确保 "设置新值" 操作的原子性,不会被其他线程打断。CompareExchange
结合循环可实现 "检查 - 更新" 的原子性(如ToggleServerInfo
方法),避免并发下的状态不一致。
可见性保证:
Interlocked
操作会强制刷新 CPU 缓存,确保所有线程看到的是最新值(避免因缓存导致的 "脏读")。
适用场景
- 简单的开关状态(如
GetServerInfo
的启用 / 禁用)。 - 计数器(如统计并发请求数、操作次数)。
- 需要原子 "检查并修改" 的逻辑(如仅当状态为关闭时才开启)。
如果你的场景涉及更复杂的状态转换(如多值状态),这种整数映射方式同样适用,只需扩展数值对应的含义即可(如 0=未初始化
、1=运行中
、2=已停止
)。