常见的锁策略

锁策略是并发编程中用于管理多个线程对共享资源访问的一种重要机制。

以下是对常见锁策略的详细总结:

1. 悲观锁/乐观锁

悲观锁

  1. 概念:悲观锁总是假设最坏的情况,即认为每次访问共享资源时都会发生冲突,因此在访问数据之前先加锁。
  2. 应用场景:适用于写操作较为频繁的环境,通过预先加锁,可以保证数据的一致性。
  3. 特点:线程在访问共享资源前必须先获得锁,否则会被阻塞。这种方式确保了数据的安全性,但可能会降低系统的并发性能。
  4. 示例:Java中的synchronized关键字和Lock接口的实现类就是悲观锁的典型代表。

乐观锁

  1. 概念:乐观锁总是假设最好的情况,即认为在数据访问过程中不会发生冲突,只在数据更新时检查是否发生了冲突。
  2. 应用场景:适用于读操作较多的环境,通过不加锁的方式提高读取操作的性能。
  3. 特点:使用版本号或时间戳等方式来检查数据在读取和写入之间是否发生了变化。如果检测到数据发生了变化,则更新操作会失败。
  4. 示例:乐观锁的常见实现方式包括版本号机制和CAS(Compare-And-Swap)算法。

2. 重量级锁/轻量级锁

重量级锁

  1. 概念:重量级锁是基于操作系统的互斥量(Mutex Lock)而实现的锁,会导致进程在用户态和内核态之间切换,相对开销较大。
  2. 应用场景:在锁竞争激烈的场景下,轻量级锁可能会升级为重量级锁。
  3. 特点:线程在获取锁失败后会进入阻塞状态,等待操作系统唤醒。这种方式确保了数据的安全性,但可能会增加线程切换的开销和延迟。
  4. 示例:Java中的synchronized在JDK 1.6之前主要基于重量级锁实现。

轻量级锁

  1. 概念:轻量级锁是相对于重量级锁而言的,它尝试在用户态解决线程冲突,减少线程切换的开销。
  2. 应用场景:适用于线程交替执行同步代码块的情况,即互斥操作不频繁的场景。
  3. 特点:通过CAS操作来尝试获取锁,如果成功则继续执行,如果失败则进行自旋等待。这种方式减少了线程切换的开销,但可能会增加CPU的消耗。
  4. 示例:JDK 1.6之后,synchronized引入了轻量级锁和偏向锁来优化性能。

3. 挂起等待锁/自旋锁

挂起等待锁

  1. 概念:当某个线程没有申请到锁的时候,该线程会被挂起,即加入到等待队列等待。当锁被释放的时候,该线程会被唤醒并重新竞争锁。
  2. 应用场景:适用于临界区运行时间较长的场景。
  3. 特点:线程在等待锁的过程中会进入阻塞状态,等待操作系统唤醒。这种方式减少了CPU的消耗,但可能会增加线程唤醒的延迟。

自旋锁

  1. 概念:当某个线程没有申请到锁的时候,该线程不会被挂起,而是每隔一段时间检测锁是否被释放。如果锁被释放了,就竞争锁;如果没有释放,过一会儿再来检测。
  2. 应用场景:适用于临界区运行时间较短的场景。
  3. 特点:线程在等待锁的过程中会进行自旋,即不断检测锁的状态。这种方式减少了线程切换的开销,但可能会增加CPU的消耗。

4. 公平锁/非公平锁

公平锁

  1. 概念:公平锁是一种按照请求顺序授予锁的机制,即先请求锁的线程会先获得锁。
  2. 应用场景:适用于需要保证线程公平性的场景。
  3. 特点:通过维护一个队列来管理等待的线程,确保每个线程都能公平地获取到锁。这种方式避免了线程饥饿的问题,但可能会增加性能开销和上下文切换的次数。

非公平锁

  1. 概念:非公平锁是一种不按照请求顺序授予锁的机制,即任何线程都有可能在任何时候获得锁。
  2. 应用场景:适用于对线程公平性要求不高的高并发场景。
  3. 特点:通常会优先考虑当前已经持有锁的线程或等待时间较短的线程,以提高系统的吞吐量。这种方式性能较高,但可能会导致某些线程长时间得不到锁。

5. 可重入锁/不可重入锁

可重入锁(Reentrant Lock)

  1. 定义:可重入锁是一种允许同一个线程多次获取同一把锁的锁机制。如果一个线程已经持有了某把锁,那么它可以再次获取这把锁而不会导致死锁。
  2. 特点
  3. 重入性:支持锁的嵌套获取,即同一个线程在持有锁的情况下,可以再次进入该锁保护的同步代码块或方法。
  4. 灵活性:相比于Java中的synchronized关键字,可重入锁提供了更多的灵活性,如尝试锁定(tryLock)、可中断的锁定(lockInterruptibly)、定时锁定(tryLock(long time, TimeUnit unit))等。
  5. 公平性与非公平性:可重入锁可以是公平的也可以是非公平的。公平锁会按照请求锁的顺序来授予锁,而非公平锁则允许“插队”。
  6. 应用场景:适用于需要嵌套同步代码块的场景,或者一个线程在持有锁的情况下,需要再次进入该锁保护的同步代码块。
  7. 示例:Java中的ReentrantLock类是可重入锁的一个实现。

6. 读写锁(Read-Write Lock)

  1. 定义:读写锁是一种允许多个读操作同时进行,但写操作会排他的锁机制。它将共享资源的访问分为读操作和写操作,以提高并发性能。
  2. 特点
  3. 分离读写操作:读写锁将读操作和写操作分离,允许多个读操作同时进行,而写操作会阻塞其他读操作和写操作。
  4. 提高并发性:通过分离读写操作,可以显著提高系统的并发性能,特别是在读操作远多于写操作的场景中。
  5. 锁降级与升级:在某些读写锁的实现中,还支持锁的降级(将写锁降级为读锁)和升级(将读锁升级为写锁),但这通常涉及到复杂的同步逻辑和潜在的死锁风险。
  6. 应用场景:适用于读多写少的场景,如缓存系统、数据库连接池等。
  7. 示例:Java中的ReentrantReadWriteLock类就是读写锁的一个实现。它包含了一个读锁和一个写锁,读锁可以被多个读线程同时持有,而写锁则是排他的。

在实际应用中,开发者应根据具体场景和需求选择合适的锁策略来优化系统的性能和并发能力。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值