在C#中的乐观锁和悲观锁
在C#中,乐观锁(Optimistic Locking)和悲观锁(Pessimistic Locking)是两种不同的并发控制策略,用于处理多线程环境下的数据一致性问题。它们的核心区别在于对数据冲突的预期和处理方式。
1. 悲观锁(Pessimistic Locking)
悲观锁假设在多线程环境下,数据冲突是常态,因此在访问共享资源时,会提前锁定资源,防止其他线程的干扰。
特点
- 提前锁定:在操作数据之前,先获取锁,确保独占访问。
- 适用场景:适用于写操作频繁、冲突概率较高的场景。
- 缺点:可能导致锁竞争,降低并发性能。
实现方式
在C#中,悲观锁可以通过lock
关键字、Monitor
类、Mutex
类等实现。
示例
public class Counter
{private int count = 0;private readonly object lockObject = new object();public void Increment(){lock (lockObject) // 悲观锁:提前锁定{count++;}}public int GetCount(){lock (lockObject) // 悲观锁:提前锁定{return count;}}
}
2. 乐观锁(Optimistic Locking)
乐观锁假设在多线程环境下,数据冲突是少数情况,因此不会提前锁定资源,而是在提交操作时检查数据是否被其他线程修改过。如果数据被修改,则放弃操作或重试。
特点
- 不提前锁定:在操作数据时不加锁,仅在提交时检查冲突。
- 适用场景:适用于读操作频繁、写操作较少的场景。
- 优点:减少锁竞争,提高并发性能。
- 缺点:需要处理冲突,可能会导致操作失败或重试。
实现方式
乐观锁通常通过版本号(Version Number)或时间戳(Timestamp)来检测数据是否被修改。
示例
public class Counter
{private int count = 0;private int version = 0; // 版本号public void Increment(){int currentVersion;int newVersion;do{currentVersion = version; // 获取当前版本号newVersion = currentVersion + 1; // 计算新版本号} while (Interlocked.CompareExchange(ref version, newVersion, currentVersion) != currentVersion);// 如果版本号更新成功,说明没有冲突count++;}public int GetCount(){return count;}
}
3. 对比
特点 | 悲观锁 | 乐观锁 |
---|---|---|
锁定时机 | 提前锁定,操作开始时加锁 | 不提前锁定,仅在提交时检查冲突 |
适用场景 | 写操作频繁,冲突概率高 | 读操作频繁,写操作较少 |
并发性能 | 低(锁竞争) | 高(减少锁竞争) |
实现方式 | lock 、Monitor 、Mutex 等 | 版本号(Version Number)、时间戳(Timestamp) |
优点 | 简单,容易实现 | 提高性能,减少锁竞争 |
缺点 | 锁竞争,性能瓶颈 | 需要处理冲突,可能重试 |
4. 使用场景
- 悲观锁:
- 适用场景:数据库事务中,当更新操作频繁且冲突概率较高时,使用悲观锁可以避免频繁的冲突处理。
- 示例:银行转账系统,多个线程同时操作同一个账户余额。
- 乐观锁:
- 适用场景:读操作频繁,写操作较少的场景,如在线购物系统中,商品信息的读取和更新。
- 示例:电商平台的商品库存更新,读取操作远多于写入操作。
5. 在数据库中的应用
- 悲观锁:
- 在数据库中,可以通过
SELECT FOR UPDATE
语句实现悲观锁,锁定记录,防止其他事务修改。 - 示例:
SELECT * FROM products WHERE id = 1 FOR UPDATE;
- 在数据库中,可以通过
- 乐观锁:
- 在数据库中,可以通过版本号或时间戳字段实现乐观锁。在更新时,检查版本号是否发生变化。
- 示例:
UPDATE products SET stock = stock - 1, version = version + 1 WHERE id = 1 AND version = @currentVersion;
总结
- 悲观锁:适合写操作频繁、冲突概率高的场景,通过提前锁定资源来避免冲突。
- 乐观锁:适合读操作频繁、写操作较少的场景,通过版本号或时间戳检测冲突,减少锁竞争,提高并发性能。
在实际开发中,可以根据具体需求选择合适的锁机制。