互斥锁、自旋锁、读写锁、乐观锁、悲观锁的区别及适用场景

🔒 互斥锁、自旋锁、读写锁、乐观锁、悲观锁的区别及适用场景

并发编程数据库事务控制中,锁是保证数据一致性的核心手段。不同类型的锁适用于不同的场景,理解它们的特点可以帮助我们在高并发系统中做出最佳选择。


1️⃣ 互斥锁(Mutex)

🔹 概念:

  • 互斥锁(Mutual Exclusion Lock,简称Mutex)是一种用于保证同一时刻只有一个线程访问资源的锁。
  • 获取锁的线程可以阻塞其他线程,直到锁被释放。

🔹 适用场景:

  • 单线程独占资源(如临界区访问)
  • I/O 操作(文件、网络等资源访问)

🔹 优缺点:

优点缺点
保证数据安全线程被阻塞,发生上下文切换,影响性能

🔹 示例(Java ReentrantLock):

Lock lock = new ReentrantLock();
lock.lock();
try {
    // 访问临界资源
} finally {
    lock.unlock();
}

2️⃣ 自旋锁(Spinlock)

🔹 概念:

  • 自旋锁是一种不主动让出 CPU,而是不断循环检查锁是否可用的锁。
  • 适用于锁持有时间很短的情况,避免线程阻塞的开销。

🔹 适用场景:

  • 多核 CPU,锁占用时间短(如 CPU 缓存同步)
  • 避免线程阻塞导致的上下文切换开销

🔹 优缺点:

优点缺点
避免线程切换的开销(适用于锁持有时间短的情况)线程会占用 CPU 资源,不适用于长时间持有锁的情况

🔹 示例(Java 自旋锁):

while (!lock.compareAndSet(false, true)) {
    // 自旋等待
}

3️⃣ 读写锁(Read-Write Lock)

🔹 概念:

  • 读写锁允许多个线程同时读取(共享读),但写入时需要独占锁(独占写)。
  • 适用于读多写少的场景,提高并发性。

🔹 适用场景:

  • 缓存系统(Redis、数据库索引)
  • 配置读取(多个线程同时读,但偶尔有写操作)

🔹 优缺点:

优点缺点
读操作并发性高,适用于读多写少的情况写操作仍然是串行的,写入时所有读线程都需要等待

🔹 示例(Java ReadWriteLock):

ReadWriteLock lock = new ReentrantReadWriteLock();

// 读锁
lock.readLock().lock();
try {
    // 读取数据
} finally {
    lock.readLock().unlock();
}

// 写锁
lock.writeLock().lock();
try {
    // 修改数据
} finally {
    lock.writeLock().unlock();
}

4️⃣ 乐观锁(Optimistic Lock)

🔹 概念:

  • 乐观锁假设数据不会被修改,在操作数据前不加锁,而是在更新时检查数据是否发生变化(如版本号)。
  • 如果数据未被其他线程修改,则更新成功;否则,需要重试。

🔹 适用场景:

  • 高并发场景(数据库更新、缓存更新)
  • 数据库事务(通过版本号 version 进行控制)

🔹 优缺点:

优点缺点
提高并发性(不锁资源)需要额外的冲突检测(可能导致重试开销)

🔹 示例(数据库版本控制):

UPDATE users 
SET balance = balance - 100, version = version + 1
WHERE id = 1 AND version = 5;
  • 只有当 version = 5 时更新才会成功,否则表示数据已被其他线程修改,需要重试。

5️⃣ 悲观锁(Pessimistic Lock)

🔹 概念:

  • 悲观锁假设数据总是会被修改,因此在操作前先加锁,防止其他线程修改数据。
  • 适用于竞争激烈的场景,确保数据一致性。

🔹 适用场景:

  • 数据库事务控制行级锁表锁
  • 高冲突资源访问(如订单扣库存)

🔹 优缺点:

优点缺点
保证数据一致性影响并发性能,可能导致锁等待

🔹 示例(数据库行锁):

SELECT * FROM users WHERE id = 1 FOR UPDATE;
  • FOR UPDATE 语句会加行锁,其他事务必须等待该事务提交后才能访问该行数据。

🔎 总结:不同锁的适用场景

锁类型特点适用场景缺点
互斥锁(Mutex)线程互斥访问,阻塞等待I/O 操作、临界区保护线程阻塞,影响性能
自旋锁(Spinlock)不让出 CPU,循环等待锁时间短的高并发任务占用 CPU 资源,锁时间长时性能下降
读写锁(Read-Write Lock)允许并发读,写互斥读多写少的场景(如缓存)写操作仍然串行,影响写性能
乐观锁(Optimistic Lock)先操作,提交时检查冲突高并发数据库更新需要额外的重试机制
悲观锁(Pessimistic Lock)操作前加锁,防止修改数据库事务、库存扣减影响并发性,可能导致死锁

🔥 面试技巧

面试官:什么时候用乐观锁,什么时候用悲观锁?
回答要点

  • 高并发场景(如订单更新)用乐观锁(减少锁等待)
  • 数据竞争激烈(如银行账户操作)用悲观锁(确保数据一致性)

面试官:自旋锁和互斥锁的区别?
回答要点

  • 互斥锁 线程会阻塞等待,发生上下文切换
  • 自旋锁 线程不阻塞,而是在循环等待(适用于锁时间短的情况)。

面试官:如何提高数据库并发?
回答要点

  • 读多写少用读写锁
  • 高并发更新用乐观锁
  • 数据一致性要求高用悲观锁

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值