簡介
Interlocked.Increment 是 .NET 中一個重要的線程安全操作方法,用於以原子方式遞增變量的值。它位於 System.Threading 命名空間中,提供了一種輕量級的線程同步機制。
這些方法包括:
| 方法 | 作用 |
|---|---|
Increment(ref int location) |
原子 +1 |
Decrement(ref int location) |
原子 -1 |
Add(ref int location, int value) |
原子加指定值 |
Exchange(ref T location, T value) |
原子交換值 |
CompareExchange(ref T location, T value, T comparand) |
CAS 操作(Compare-And-Swap) |
Read(ref long location) |
原子讀取 long 值 |
這些操作都是 線程安全且無鎖 (lock-free) 的。
核心概念與作用
原子操作定義
- 不可分割性:操作要麼完全執行,要麼完全不執行
- 線程安全:多線程環境下保證操作完整性
- 無鎖機制:避免傳統鎖帶來的性能開銷
核心特性
| 特性 | 説明 |
|---|---|
| 線程安全 | 無需額外同步機制 |
| 硬件級原子性 | 使用 CPU 原子指令實現 |
| 內存屏障 | 確保操作前後內存一致性 |
| 高性能 | 比鎖機制快 10-50 倍 |
底層實現原理
x86/x64 架構實現
; x86 實現
lock xadd [location], eax
; x64 實現
lock xadd [location], rax
lock前綴:鎖定內存總線,確保操作原子性xadd指令:交換並相加寄存器與內存值
基本用法
using System;
using System.Threading;
class Program
{
private static int _counter = 0;
static void Main()
{
var threads = new Thread[10];
for (int i = 0; i < 10; i++)
{
threads[i] = new Thread(IncrementCounter);
threads[i].Start();
}
foreach (var t in threads)
t.Join();
Console.WriteLine($"最終計數值: {_counter}");
}
static void IncrementCounter()
{
for (int i = 0; i < 1000; i++)
{
Interlocked.Increment(ref _counter);
}
}
}
輸出:
最終計數值: 10000
即使多個線程併發操作同一個變量,也不會出現競爭問題。
為什麼不能直接用 _counter++
_counter++ 實際上是三步操作:
int temp = _counter;
temp = temp + 1;
_counter = temp;
在多線程環境中,這三步可能被打斷,比如:
| 線程A | 線程B |
|---|---|
讀取 _counter = 0 |
讀取 _counter = 0 |
+1 → 1 |
+1 → 1 |
寫回 _counter = 1 |
寫回 _counter = 1 |
最終 _counter = 1,而不是 2。
這就是競爭條件(race condition)。
Interlocked.Increment 內部使用 CPU 的原子指令(如 x86 的 LOCK INC),
確保操作不可中斷,因此絕對線程安全。
返回值
Interlocked.Increment 會返回自增後的值:
int count = 0;
int newValue = Interlocked.Increment(ref count);
Console.WriteLine(newValue); // 1
Console.WriteLine(count); // 1
所以它可以直接用於生成唯一 ID、計數等邏輯。
支持的類型
| 方法 | 支持的類型 |
|---|---|
Interlocked.Increment |
int, long |
Interlocked.Decrement |
int, long |
Interlocked.Add |
int, long |
Interlocked.Exchange |
int, long, float, double, object |
Interlocked.CompareExchange |
同上 |
性能分析
相比於使用 lock 的同步方式:
lock(_lockObj)
{
_counter++;
}
Interlocked.Increment:
✅ 無鎖操作(Lock-free)
✅ 內核級原子性(基於 CPU 指令)
✅ 極高性能(納秒級)
實測在多線程計數場景中性能提升 5~10 倍以上。
非常適合高頻次計數(如統計請求量、日誌寫入次數、對象實例數)。
完整的原子操作方法集
using System;
using System.Threading;
class InterlockedCompleteExample
{
private static int _counter = 0;
private static long _bigCounter = 0;
private static int _value = 10;
private static object _syncObject = new object();
static void DemonstrateAllMethods()
{
// 1. Increment - 遞增
int result1 = Interlocked.Increment(ref _counter);
Console.WriteLine($"After Increment: {_counter}, Returned: {result1}");
// 2. Decrement - 遞減
int result2 = Interlocked.Decrement(ref _counter);
Console.WriteLine($"After Decrement: {_counter}, Returned: {result2}");
// 3. Add - 加法
int result3 = Interlocked.Add(ref _counter, 5);
Console.WriteLine($"After Add(5): {_counter}, Returned: {result3}");
// 4. Exchange - 交換
int original = Interlocked.Exchange(ref _value, 20);
Console.WriteLine($"After Exchange: {_value}, Original: {original}");
// 5. CompareExchange - 比較並交換
int comparand = 20;
int newValue = 30;
int result5 = Interlocked.CompareExchange(ref _value, newValue, comparand);
Console.WriteLine($"After CompareExchange: {_value}, Returned: {result5}");
// 6. Read - 讀取 long 類型(確保在32位系統上原子讀取)
long readResult = Interlocked.Read(ref _bigCounter);
Console.WriteLine($"Read long value: {readResult}");
// 7. And - 位與操作(.NET 5+)
// Interlocked.And(ref _value, 0x0F);
// 8. Or - 位或操作(.NET 5+)
// Interlocked.Or(ref _value, 0xF0);
}
}
典型應用場景
多線程計數器
private static int _activeConnections;
public static void OnClientConnect()
{
var current = Interlocked.Increment(ref _activeConnections);
Console.WriteLine($"連接數增加到 {current}");
}
public static void OnClientDisconnect()
{
var current = Interlocked.Decrement(ref _activeConnections);
Console.WriteLine($"連接數減少到 {current}");
}
分配唯一自增 ID
private static int _nextId = 0;
public static int GetNextId()
{
return Interlocked.Increment(ref _nextId);
}
控制併發訪問次數
private static int _running = 0;
public async Task ProcessAsync()
{
if (Interlocked.Increment(ref _running) > 5)
{
Console.WriteLine("超過併發限制,拒絕執行");
Interlocked.Decrement(ref _running);
return;
}
try
{
await DoWorkAsync();
}
finally
{
Interlocked.Decrement(ref _running);
}
}
高級用法
無鎖棧實現
public class LockFreeStack<T>
{
private class Node
{
public T Value { get; }
public Node Next { get; set; }
public Node(T value)
{
Value = value;
}
}
private Node _head;
public void Push(T value)
{
var newNode = new Node(value);
Node oldHead;
do
{
oldHead = _head;
newNode.Next = oldHead;
}
while (Interlocked.CompareExchange(ref _head, newNode, oldHead) != oldHead);
}
public bool TryPop(out T value)
{
Node oldHead;
do
{
oldHead = _head;
if (oldHead == null)
{
value = default;
return false;
}
}
while (Interlocked.CompareExchange(ref _head, oldHead.Next, oldHead) != oldHead);
value = oldHead.Value;
return true;
}
public bool IsEmpty => _head == null;
}
線程安全的對象池
public class ObjectPool<T> where T : class, new()
{
private class Node
{
public T Value { get; }
public Node Next { get; set; }
public Node(T value)
{
Value = value;
}
}
private Node _head;
private int _count = 0;
private readonly int _maxSize;
public ObjectPool(int maxSize = 100)
{
_maxSize = maxSize;
}
public void Return(T item)
{
if (Interlocked.Read(ref _count) >= _maxSize)
{
return; // 池已滿,丟棄對象
}
var newNode = new Node(item);
Node oldHead;
do
{
oldHead = _head;
newNode.Next = oldHead;
}
while (Interlocked.CompareExchange(ref _head, newNode, oldHead) != oldHead);
Interlocked.Increment(ref _count);
}
public T Get()
{
Node oldHead;
do
{
oldHead = _head;
if (oldHead == null)
{
Interlocked.Increment(ref _count);
return new T();
}
}
while (Interlocked.CompareExchange(ref _head, oldHead.Next, oldHead) != oldHead);
Interlocked.Decrement(ref _count);
return oldHead.Value;
}
public int Count => (int)Interlocked.Read(ref _count);
}
與 lock、Monitor 的區別
| 特性 | Interlocked | lock / Monitor |
|---|---|---|
| 是否鎖住線程 | 否 | 是 |
| 原子性 | ✅ | ✅ |
| 是否可中斷 | 不可 | 可被其他線程等待 |
| 性能 | 極高 | 一般 |
| 適用場景 | 簡單數值、指針操作 | 多步複雜邏輯 |
- 如果只是“計數/標誌位更新”,用
Interlocked; - 如果涉及多個變量或邏輯組合,用
lock。
CompareExchange (CAS) 補充理解
Interlocked.CompareExchange 是構建更復雜無鎖結構的核心:
int location = 0;
int newValue = 1;
int expected = 0;
int old = Interlocked.CompareExchange(ref location, newValue, expected);
- 如果
location == expected→ 把location改成newValue; - 否則什麼都不做;
- 返回修改前的舊值。
這就是經典的 Compare-And-Swap (CAS),
是無鎖隊列、無鎖堆棧、無鎖緩存等的基礎原語。
與 async/await 的結合注意事項
Interlocked 是同步原子操作,適用於多線程併發,不涉及異步上下文。
即使在 async 方法中使用,也完全沒問題:
private static int _count;
public async Task LogAsync()
{
Interlocked.Increment(ref _count);
await File.AppendAllTextAsync("log.txt", $"{_count}\n");
}
- 它不會保證異步順序;
- 它保證計數線程安全。
總結
| 特性 | Interlocked.Increment |
|---|---|
| 命名空間 | System.Threading |
| 返回值 | 自增後的值 |
| 線程安全 | ✅ 原子操作 |
| 鎖機制 | 無鎖 |
| 支持類型 | int, long |
| 性能 | 極高 |
| 應用場景 | 計數、ID生成、併發控制、原子狀態更新 |
| 替代方案 | lock、Monitor、Volatile、CAS |