悲观锁和乐观锁详细讲解及代码示例

悲观锁和乐观锁是并发编程中常用的两种锁机制。它们的实现方式不同,是在保证数据一致性的前提下提高并发性能的有效手段。

悲观锁,在进行并发操作时,始终持有锁,认为并发操作会发生冲突,因此必须加锁以保证数据一致性。常用的实现方式是通过数据库的行级锁或者排它锁来实现。相比于乐观锁,悲观锁的安全性更高,但是并发性能较差,因为一旦出现竞争,其他线程必须等待当前线程执行完后才能获取锁。

乐观锁,相反的,认为并发操作不会引起冲突,没有加锁的情况下进行并发操作,当更新数据时,检查版本号是否一致,如果版本号不一致,则表明数据发生了变化,应该重新读取数据进行操作。因此,乐观锁适用于并发程度较高但是写操作较少的情况下。常用的实现方式是使用CAS(Compare and Swap)算法,通过原子性的比较和交换操作,保证此次读取的数据版本与实际操作的数据版本一致性。相比于悲观锁,乐观锁的并发性能更好,但是如果并发操作较为频繁,并且数据冲突的概率较大,可能会导致其中一部分线程需要频繁的重试。

下面是Java中悲观锁和乐观锁的代码示例:

悲观锁示例:

public synchronized void updateData(Object data) {
   // 从数据库读取数据
   Object dbData = readFromDataBase();
   // 更新数据
   updateData(dbData, data);
}

private Object readFromDataBase() {
   //查询数据,使用select for update实现行级锁
   return queryForData();
}

乐观锁示例:

public void updateData(Object data) {
   int version = getVersion();
   while (true) {
      // 从数据库读取数据和版本信息
      Object dbData = readFromDataBase();
      int dbVersion = getVersion();
      if (dbVersion == version) {
         // 更新数据
         updateData(dbData, data);
         break;
      } else {
         // 版本不一致,说明数据已经更新,需要重试
         version = dbVersion;
      }
   }
}

private int getVersion() {
   //查询数据的版本号
   return queryForVersion();
}

在实际应用中,我们需要根据具体的业务场景来选择悲观锁或者乐观锁。

使用悲观锁需要注意锁的粒度,如果锁的粒度过大,会导致性能问题,如果锁的粒度过小,会增加锁冲突的概率。使用悲观锁还需要注意死锁的情况,因为悲观锁是一种阻塞式的锁,如果多个线程都持有锁并且互相等待对方释放锁,就会导致死锁。因此,在使用悲观锁的时候,要避免锁的嵌套和锁的持有时间过长。

使用乐观锁需要注意数据的一致性,由于更新数据时需要检查版本号,因此在高并发场景下,数据存在竞争的概率较大,如果并发程度过高,可能导致大量线程不断的重试。为了避免这种情况,可以采用一些补偿机制,例如增加随机的重试间隔时间,或者在一定的重试次数内增量递增等策略。此外,使用乐观锁还需要注意版本号的生成方式,尽可能的避免版本号的重复,否则会导致更新操作无法进行。

综上所述,悲观锁和乐观锁都有各自的适用场景,在实际应用中,需要结合具体业务场景和性能需求进行选择。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
悲观锁乐观锁都是用于并发控制的技术。 悲观锁的思想是,在整个数据处理过程中,将数据进行加锁,防止其他线程对该数据进行修改。因此,其他线程需要等待锁被释放才能对数据进行修改。悲观锁的缺点是效率低下,因为它需要占用锁定资源的时间较长。 乐观锁的思想是,先假设所有线程都能成功修改数据,并进行修改。当某个线程提交时,先检查该数据是否被其他线程修改,如果未被修改,则提交成功,如果已经被修改,则后提交的线程需要进行重试。乐观锁的优点是效率高,缺点是可能存在矛盾和并发问题。 实现悲观锁,可以使用数据库中的行锁机制,在事务处理期间锁定某些数据行,防止其他事务对该数据进行修改。实现乐观锁,可以使用 CAS(Compare and Swap)算法,在对数据进行修改之前,先检查该数据是否已经被其他线程修改,如果该数据值未被修改,则执行修改,否则重试修改操作。 以下是Java中使用乐观锁代码示例: ```java public class Account { private int balance; private int version; // 存款操作 public void deposit(int amount) { while(true) { int oldVersion = version; int newVersion = oldVersion + 1; int newBalance = balance + amount; if(compareAndSwap(oldVersion, newVersion, newBalance)) { balance = newBalance; version = newVersion; break; } } } // 使用CAS操作原子性进行比较 private boolean compareAndSwap(int oldVersion, int newVersion, int newBalance) { synchronized(this) { if(version == oldVersion) { balance = newBalance; version = newVersion; return true; } return false; } } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

左安青

感谢各位大佬,您鼓励是我的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值