高级java每日一道面试题-2025年01月22日-JVM篇-乐观锁和悲观锁的理解及如何实现,有哪些实现方式?

如果有遗漏,评论区告诉我进行补充

面试官: 乐观锁和悲观锁的理解及如何实现,有哪些实现方式?

我回答:

一、乐观锁与悲观锁的概念

1. 乐观锁
  • 定义:乐观锁假设并发冲突发生的概率较低,因此不会主动加锁,而是在提交更新时检查是否有其他事务已经修改过数据;如果有,则拒绝提交或提示用户重新尝试。
  • 特点
    • 不会阻塞其他线程的操作,允许并发执行。
    • 在更新时通过版本号、时间戳或哈希值等方式验证数据是否被修改。
    • 适用于读多写少的场景,能显著提高并发性能。
2. 悲观锁
  • 定义:悲观锁假设并发冲突发生的概率较高,因此每次操作共享资源时都会加锁,以确保其他线程不能同时访问或修改该资源。
  • 特点
    • 加锁期间其他线程必须等待,直到当前持有锁的线程释放锁。
    • 阻塞式操作,可能导致性能瓶颈,特别是在高并发环境下。
    • 适用于写多读少或者对数据一致性要求极高的场景。

二、乐观锁的实现方式

1. 版本号机制
  • 描述:在数据库中为每条数据记录一个版本号字段,在更新操作时比较当前事务的版本号与数据库中的版本号是否一致。
  • 流程
    • 如果一致,则执行更新操作,并将版本号递增。
    • 如果不一致,则说明有其他线程已经修改了数据,需要重新尝试更新操作。
  • 示例 (使用JPA的@Version注解):
java 复制代码
@Entity
public class Product {
    @Id
    private Long id;
    
    @Version
    private Integer version;

    // 其他属性...
}
2. 时间戳机制
  • 描述:类似于版本号机制,但使用时间戳来记录数据的最后修改时间。
  • 流程:当执行更新操作时,会比较当前事务的时间戳与数据库中的时间戳是否一致,从而决定是否执行更新操作。
3. CAS(Compare-and-Swap)算法
  • 描述:CAS是一种无锁算法,它通过比较并交换的方式实现对共享变量的原子更新。
  • 流程:在更新数据前检查数据的当前值是否与预期值相等,如果相等则进行更新,否则重新尝试更新操作。
  • 示例 (使用AtomicInteger类):
java 复制代码
AtomicInteger counter = new AtomicInteger(0);

public boolean incrementIfEquals(int expected, int newValue) {
    return counter.compareAndSet(expected, newValue);
}

三、悲观锁的实现方式

1. synchronized 关键字
  • 描述:Java中最常见的实现悲观锁的方式之一。可以在方法或代码块上锁定对象,确保同一时间只有一个线程可以访问共享资源。
  • 示例
java 复制代码
public synchronized void updateData() {
    // 修改数据的逻辑
}
2. Lock 接口
  • 描述 :Java 5提供了Lock接口来替代synchronized关键字,提供了更灵活的锁机制。
  • 功能:支持公平锁和非公平锁、可中断的获取锁、尝试获取锁等多种功能。
  • 常见实现类ReentrantLock等。
  • 示例
java 复制代码
private final ReentrantLock lock = new ReentrantLock();

public void updateData() {
    lock.lock();
    try {
        // 修改数据的逻辑
    } finally {
        lock.unlock();
    }
}
3. 数据库层面的悲观锁
  • 描述 :在数据库中,悲观锁通常通过SQL语句实现,如使用SELECT ... FOR UPDATE语句来锁定查询到的行,阻止其他事务的读写操作。
  • 示例
sql 复制代码
SELECT * FROM products WHERE id = ? FOR UPDATE;

四、应用场景

1. 乐观锁的应用场景
  • 适用情况:适用于并发冲突较少、并发性能要求较高的场景。
  • 示例:电商网站的库存扣减,因为库存数据的变化不是非常频繁,可以使用乐观锁来提高并发性能。
2. 悲观锁的应用场景
  • 适用情况:适用于并发冲突较多、数据一致性要求较高的场景。
  • 示例:金融系统的资金转账,由于资金数据的变化非常敏感且频繁,需要使用悲观锁来确保数据的一致性和安全性。

总结

乐观锁和悲观锁是Java并发编程中两个重要的概念,它们各自具有不同的特点和适用场景:

  • 选择合适的锁策略:根据应用的具体需求选择适当的锁策略。对于写多读少或对数据一致性要求极高的场景,可以选择悲观锁;而对于读多写少的场景,乐观锁则更为适合。
  • 结合实际案例:在面试中能够准确阐述这些概念,并结合实际案例讨论其应用场景,将极大地展示你的专业水平和技术深度。
  • 优化性能:理解锁的工作原理可以帮助开发者避免常见的并发问题,并写出更高效的并发代码。例如,在高并发环境中,合理运用乐观锁可以大大提升系统的吞吐量和响应速度。
相关推荐
我命由我1234537 分钟前
Android 开发问题:为 PDFView 设置一个带有黑色边框的背景 drawable,但边框没有生效
android·java·java-ee·android studio·android jetpack·android-studio·android runtime
都叫我大帅哥3 小时前
从Python到Java:为什么企业级Agent最终会选择Java?
java·ai编程
wanderist.3 小时前
Lambda表达式在算法竞赛中的应用
java·开发语言·算法
腻害兔4 小时前
【若依项目-产品经理视角】RuoYi-Vue-Pro 源码拆解:IM 即时通讯模块,一个被低估的「全功能聊天系统」
java·前端·vue.js·产品经理·ai编程
心念枕惊5 小时前
.NET CORE 授权进阶-角色、策略与动态权限实现
java·前端·.netcore
景同学6 小时前
把 AI 用到线上运维:可行、有效,前提是喂足信息——一次 Full GC 排障实录
java·人工智能·后端
C++、Java和Python的菜鸟7 小时前
第7章 后端Web实战(Tlias系统)
java
憧憬成为java架构高手的小白7 小时前
黑马八股--spring框架学习
java·学习·spring
唐青枫7 小时前
Java Picocli 实战详解:用注解写出好用的命令行工具
java
X-⃢_⃢-X8 小时前
四、OpenFeign远程调用
java·微服务·springboot·springcloud