乐观锁和悲观锁区别以及使用场景

2023-11-08

乐观锁和悲观锁是并发控制中两种不同的策略,用于解决多个线程或进程同时访问和修改共享数据时可能出现的并发问题。

  1. 悲观锁

悲观锁的基本思想是,在数据被访问时,假设会有其他的线程或进程也会访问这个数据,所以在访问数据之前,先对数据进行加锁,确保只有当前的线程或进程可以访问和修改数据。悲观锁在执行操作之前总是获取锁,确保在修改数据的时候数据不会被其他的线程或进程修改,这种锁的机制会导致其他的线程或进程在访问该数据时会被阻塞。悲观锁在MySQL数据库中,通过使用SELECT ... FOR UPDATE或者SELECT ... LOCK IN SHARE MODE语句进行实现。在Java中,synchronized关键字和ReentrantLock类也是悲观锁的实现方式。

以下是一个使用悲观锁的示例Java代码片段,使用synchronized关键字来实现:

public synchronized void updateBalance(int accountId, double amount) {
    double balance = getBalance(accountId);
    balance += amount;
    setBalance(accountId, balance);
}
  1. 乐观锁

乐观锁的基本思想是,在数据被访问时,假设不会有其他的线程或进程也会访问这个数据,所以不对数据进行加锁。在执行修改操作之前,先读取数据的版本号或者时间戳等标识,将其与执行修改操作时的版本号或者时间戳进行比较,如果相同则表示可以执行修改操作,如果不同则表示数据已经被其他的线程或进程修改,当前的操作将失败,需要重新执行。乐观锁在MySQL数据库中,通过使用乐观锁机制的数据类型,如TIMESTAMP和ROWVERSION等来实现。在Java中,乐观锁的实现方式包括使用AtomicInteger和AtomicLong等原子变量,以及使用版本号机制等。

以下是一个使用乐观锁的示例Java代码片段,使用AtomicInteger类来实现:

private AtomicInteger balance = new AtomicInteger();

public void updateBalance(int accountId, double amount) {
    int oldBalance, newBalance;
    do {
        oldBalance = balance.get();
        newBalance = oldBalance + amount;
    } while (!balance.compareAndSet(oldBalance, newBalance));
}

以上是乐观锁和悲观锁的区别及其在Java语言和MySQL数据库中的示例说明。需要注意的是,乐观锁和悲观锁并非绝对的对立面,而是不同的策略,每种策略在不同的场景下有不同的适用性和优缺点

  1. 乐观锁和悲观锁的比较

乐观锁和悲观锁都有各自的优点和缺点,应根据实际应用场景和需求选择合适的锁机制。

乐观锁相对于悲观锁而言,具有以下优点:

  • 可以提高并发性能:乐观锁不需要等待锁,因此能够避免因等待锁而产生的阻塞和死锁问题,提高并发性能;

  • 适用性更广:乐观锁对读操作的性能影响比较小,适用于读多写少的场景;

  • 实现简单:乐观锁实现简单,代码量较少。

但是,乐观锁也存在以下缺点:

  • 可能产生冲突:由于乐观锁假设在数据被访问时不会有其他线程或进程对其进行修改,因此在多个线程或进程同时对同一个数据进行修改时,可能会产生冲突,导致某些操作失败,需要重新执行;

  • 实现难度较大:乐观锁需要额外的版本号或时间戳等标识,需要确保其正确性,实现难度相对较大。

悲观锁相对于乐观锁而言,具有以下优点:

  • 可以避免冲突:悲观锁在执行操作之前总是获取锁,确保在修改数据的时候数据不会被其他的线程或进程修改,避免了冲突问题;

  • 实现相对简单:悲观锁的实现相对简单,常用的数据库和编程语言都提供了对悲观锁的支持。

但是,悲观锁也存在以下缺点:

  • 性能较低:由于悲观锁需要等待锁,因此可能会产生阻塞和死锁问题,降低并发性能;

  • 适用性较窄:悲观锁对读操作的性能影响比较大,适用于读写操作相对平衡的场景。

综上所述,乐观锁和悲观锁各有优缺点,应根据实际应用场景和需求选择合适的锁机制。在实际应用中,也可以将两种锁机制结合使用,充分利用各自的优势,提高并发性能和数据访问的准确性。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

乐观锁和悲观锁区别以及使用场景 的相关文章

  • 图像在 3D 空间中绕 Y 轴旋转

    我有一个 BufferedImage 我想用 theta 角而不是仿射变换绕 Java 中的 Y 轴旋转图像 图片 旋转将如下图所示 矩形将是图像 我可以通过旋转图像的每个像素并绘制图像来做到这一点 因为我必须旋转很多图像 所以我认为这不是
  • Java:Swing:设置JButton的位置

    我想实现以下布局 OK
  • 是否有任何理由使用 ZoneId.of("UTC") 而不是 ZoneOffset.UTC ?

    有什么理由使用ZoneId of UTC 代替ZoneOffset UTC 我们知道两者之间的区别 如ZoneOffset UTC 和 ZoneId of UTC 之间有什么区别 https stackoverflow com questi
  • Sails 嵌套模型集合

    我有 3 个型号 用户模型 module exports schema true attributes login type string required true hosts collection host via owners acc
  • 如何使用Gson将JSONArray转换为List?

    在我的 Android 项目中 我试图将收到的 JSONArray 转换为列表 在 的帮助下这个答案 https stackoverflow com questions 8371274 how to parse json array in
  • java内存不足然后退出

    我有一个必须分析大文件的软件 限制输入或提供无限内存都不是一个选择 所以我必须忍受飞行的 OOME 因为 OOME 只杀死线程 所以我的软件运行在一些糟糕的状态 从外面看一切都很好 因为进程正在运行 但在内部却是脑死亡 我想拔掉它的插头 但
  • 删除 ibdata1 后 MySQL 表消失了

    几天前 经过一番谷歌搜索后 我发现了这篇文章 我无法再让 mysql 运行了 xampp XAMPP MySQL 意外关闭 https stackoverflow com questions 18022809 xampp mysql shu
  • 在 Hibernate 的 XML 配置文件中指定默认值

    我通过映射配置文件配置 Hibernate
  • 将序列化数据发送到 servlet 时出现 java.io.EOFException

    我正在尝试从 Java 本地应用程序上传一个包含文件到服务器的对象 我的计划是 在 tomcat 上运行的 servlet 将使用以下方法获取对象ObjectInputStream in the doGet方法 但我得到一个EOFExcep
  • mysql 准备好的语句错误:MySQLSyntaxErrorException

    我使用准备好的语句编写了选择语句 每次尝试运行都会出现此错误 我如何克服这个错误 我的jdbc连接器是mysql connector java 5 1 13 bin jar 我的代码 public Main add ad to getAdD
  • 在Android项目中引用(纯java)项目(找不到类)

    我试图在我的 Android 项目中引用一个纯 java 项目 gt Java 项目有一大堆我需要使用的类 哦 正如第一个回复所指出的 我正在使用 eclipse 是的 唯一的问题是 我总是找不到类 XXX 从方法 com example
  • 如何让 Camel FTP 按需只获取一次

    我对骆驼还很陌生 我一直在尝试让 Camel 根据需要仅通过 FTP 获取单个文件一次 我无法让它发挥作用 这是我尝试过的 让我知道什么是最好的方法以及我的代码有什么问题 1 读取文件后发送一条空消息当收到空消息时 停止路由 from di
  • MySQL 错误 1264:列的值超出范围

    As I SETMySQL 中的 cust fax 表如下所示 cust fax integer 10 NOT NULL 然后我插入这样的值 INSERT INTO database values 3172978990 但随后它说 错误 1
  • 致命异常:OkHttp 调度程序

    我在 Android 应用程序中使用 OkHttp 库向天气 API 发出 Web 请求 我已经实现了我的代码 但在执行请求时遇到了致命异常 我也已经在我的清单中添加了互联网权限 MainActivity java private Curr
  • 如何预先填充 JFileChooser 将“文件名”?

    我打算用数据库中的名称填充 JFileChooser 但使用标准 JFileChooser 对话框进行加载 删除 保存和另存为 我想给用户留下这样的印象 他们正在处理文件系统 而在后端使用数据库来保存更改 用户不应该能够浏览到不同的目录进行
  • 使用 ProcessBuilder 启动 CMD

    我尝试使用以下代码在 Windows 中启动 CMD 应用程序 但它无法按预期工作 来自不同网站的几个示例表明 cmd 作为 ProcessBuilder 构造中的参数应该有效 我需要做什么才能让我的 Java 应用程序在 Windows
  • 找出对象列表中是否包含具有指定字段值的内容?

    我有一个从数据库收到的 DTO 列表 它们有一个 ID 我想确保我的列表包含具有指定 ID 的对象 显然 在这种情况下创建具有预期字段的对象不会有帮助 因为 contains 调用 Object equals 并且它们不会相等 我想出了这样
  • Elastic Beanstalk 上的 Django + MySQL - 查询 MySQL 时出错

    当我在 Elastic beanstalk 上托管的 Django 应用程序上查询 MySQL 时 出现错误 错误说 admin login 处出现操作错误 1045 用户 adminDB 172 30 23 5 的访问被拒绝 使用密码 Y
  • 如何将元素添加到通用集合

    我想知道如何将专用对象添加到通用集合中 我正在使用以下代码 Collection
  • Spring Boot 2 中的 401 代替 403

    With 春季启动 https projects spring io spring boot 1 5 6 发布我能够发送 HTTP 状态代码401代替403如中所述如果请求未经身份验证的uri 如何让Spring Security响应未经授

随机推荐