我的编程空间,编程开发者的网络收藏夹
学习永远不晚

浅谈一下Java中的悲观锁和乐观锁

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

浅谈一下Java中的悲观锁和乐观锁

悲观锁和乐观锁是面试高频问题之一,本文将对悲观锁和乐观锁简单的进行一个介绍。

悲观锁(Pessimistic Locking)

悲观锁在并发环境中认为数据随时会被其他线程修改,因此每次在访问数据时都会加锁,直到操作完成后才释放锁。悲观锁适用于写操作多、竞争激烈的场景,比如多个线程同时对同一数据进行修改或删除操作的情况。悲观锁可以保证数据的一致性,避免脏读、幻读等问题的发生

悲观锁就像一个大保安,总是认为有坏人想要偷走共享资源,于是它把资源护得紧紧的,不让任何人接近,同时还会排队等待资源,想要使用就得先获取锁,这样虽然安全可靠,但是也会导致效率低下,因为别的线程必须等待锁的释放才能继续执行。

Java中常用的悲观锁是synchronized关键字和ReentrantLock类。

使用synchronized关键字实现悲观锁的代码如下:

synchronized (lock) {
    //访问共享资源的代码块
}

使用ReentrantLock实现悲观锁的代码如下:

ReentrantLock lock = new ReentrantLock();
lock.lock();
try {
    //访问共享资源的代码块
} finally {
    lock.unlock();
}

悲观锁存的问题:

  • 效率低:悲观锁需要获取锁才能进行操作,当有多个线程需要访问同一份数据时,每个线程都需要先获取锁,然后再进行操作,如果锁竞争激烈,就会导致线程等待锁的释放,浪费了大量的时间。
  • 容易引起死锁:悲观锁在获取锁的过程中,如果获取不到就会一直等待,如果不同的线程都在等待对方释放锁,就会导致死锁的情况出现。
  • 可能会引起线程阻塞:当某个线程获取到锁时,其他线程需要等待,如果等待的时间过长,就会导致线程阻塞,影响应用的性能。

乐观锁

乐观锁在并发环境中认为数据一般情况下不会被其他线程修改,因此在访问数据时不加锁,而是在更新数据时进行检查。如果检查到数据被其他线程修改,则放弃当前操作,重新尝试更新。

乐观锁适用于读操作多、写操作少的场景,比如多个线程同时对同一数据进行读取操作的情况。乐观锁可以减少锁的竞争,提高系统的并发性能。

乐观锁就像一个乐天派,总是认为没有坏人想要偷走共享资源,于是它就不怎么防范,直接对资源进行操作,如果没有其他线程对资源进行修改,操作就会成功,否则就会进行重试,这样虽然效率高,但是如果多个线程同时进行修改,就会导致竞争和冲突,需要进行额外的处理。

Java中常用的乐观锁是基于CAS(Compare and Swap,比较和交换)算法实现的。

CAS操作包括三个操作数:内存地址V旧的预期值A新的值B。CAS操作首先读取内存地址V中的值,如果该值等于旧的预期值A,那么将内存地址V中的值更新为新的值B;

否则,不进行任何操作。在更新过程中,如果有其他线程同时对该共享资源进行了修改,那么CAS操作会失败,此时需要重试更新操作。

下面是一段基于CAS算法实现的乐观锁代码:

// 假设共享资源为变量value,初始值为1
AtomicInteger value = new AtomicInteger(1);
// 假设旧的预期值为1,新的值为2
int expect = 1;
int update = 2;

// 使用CAS操作更新共享资源的值
while (true) {
    // 读取共享资源的当前值
    int current = value.get();
    // 如果当前值等于旧的预期值,使用CAS操作将新的值更新到共享资源中
    if (current == expect) {
        if (value.compareAndSet(expect, update)) {
            // 更新成功,退出循环
            break;
        } else {
            // 更新失败,可能是因为其他线程修改了共享资源的值,重试更新操作
            continue;
        }
    } else {
        // 当前值不等于旧的预期值,说明共享资源的值已经被其他线程修改,重试更新操作
        continue;
    }
}

在这段代码中,内存地址V对应的是AtomicInteger对象value旧的预期值A对应的是变量expect新的值B对应的是变量update。使用AtomicInteger对象可以保证CAS操作的原子性,即只有一个线程能够成功更新共享资源的值。使用compareAndSet方法可以判断共享资源的值是否等于旧的预期值,并尝试将新的值更新到共享资源中。如果更新成功,就退出循环;否则,说明共享资源的值已经被其他线程修改,需要重试更新操作。

在实际应用中,乐观锁的实现通常比这个简单实现要复杂。例如,在对数据库中的数据进行更新时,需要在更新操作中同时更新版本号和其他字段的值,并且需要处理更新失败和重试的情况。

乐观锁存在的问题

CAS虽然很⾼效的解决原⼦操作,但是CAS仍然存在三⼤问题:ABA问题自旋时间过长只能保证单个变量的原子性

  • ABA问题:CAS算法在比较和替换时只考虑了值是否相等,而没有考虑到值的版本信息。如果一个值在操作过程中被修改了两次,从原值变成新值再变回原值,此时CAS会认为值没有发生变化,从而出现操作的错误。为了解决ABA问题,可以在共享资源中增加版本号,每次修改操作都将版本号加1,从而保证每次更新操作的唯一性。在更新数据时先读取当前版本号,如果与自己持有的版本号相同,则可以更新数据,否则更新失败。版本号算法可以避免ABA问题,但需要维护版本号,增加了代码复杂度和内存开销。
  • 自旋时间过长:由于CAS算法在失败时会一直自旋,等待共享变量可用,如果共享变量一直不可用,就会出现自旋时间过长的问题,浪费CPU资源。
  • 只能保证单个变量的原子性:CAS算法只能保证单个变量的原子性,如果需要多个变量的原子操作,就需要使用锁等其他方式进行保护。

悲观锁和乐观锁的对比

悲观锁乐观锁
性能
数据一致性
实现复杂度简单复杂
加锁方式基于锁机制基于版本号机制
应用场景读少写多读多写少
存在的问题效率低、容易引起死锁、可能会引起线程阻塞ABA问题、自旋时间过长、只能保证单个变量的原子性

总结

悲观锁和乐观锁各有优缺点,应根据具体的业务场景和性能需求来选择合适的锁机制。在实际应用中,也可以考虑使用两种锁机制的组合,例如在高并发读写的情况下,可以使用乐观锁来提高读操作的效率,同时在写操作时使用悲观锁来保证数据的一致性。

到此这篇关于浅谈一下Java中的悲观锁和乐观锁的文章就介绍到这了,更多相关Java悲观锁和乐观锁内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

浅谈一下Java中的悲观锁和乐观锁

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

浅谈一下Java中的悲观锁和乐观锁

这篇文章主要介绍了一下Java中的悲观锁和乐观锁,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
2023-05-16

java中乐观锁与悲观锁的概念

这篇文章主要介绍“java中乐观锁与悲观锁的概念”,在日常操作中,相信很多人在java中乐观锁与悲观锁的概念问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”java中乐观锁与悲观锁的概念”的疑惑有所帮助!接下来
2023-06-19

Java中的乐观锁和悲观锁简单介绍

这篇文章主要介绍“Java中的乐观锁和悲观锁简单介绍”,在日常操作中,相信很多人在Java中的乐观锁和悲观锁简单介绍问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java中的乐观锁和悲观锁简单介绍”的疑惑有所
2023-06-02

MySQL中的悲观锁与乐观锁

在关系型数据库中,悲观锁与乐观锁是解决资源并发场景的解决方案,接下来将详细讲解一下这两个并发解决方案的实际使用及优缺点。 首先定义一下数据库,做一个最简单的库存表,如下设计:CREATE TABLE `order_stock` (`id`
2022-05-15

Java悲观锁和乐观锁机制是什么

本篇内容主要讲解“Java悲观锁和乐观锁机制是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java悲观锁和乐观锁机制是什么”吧!1、锁机制简介并发编程中一个最关键的问题,多线程并发处理同一
2023-06-02

java中悲观锁和乐观锁有什么区别

本篇文章给大家分享的是有关java中悲观锁和乐观锁有什么区别,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。Java可以用来干什么Java主要应用于:1. web开发;2. An
2023-06-14

Java中的悲观锁与乐观锁怎么掌握

要掌握Java中的悲观锁和乐观锁,可以遵循以下步骤:1. 了解悲观锁和乐观锁的概念:- 悲观锁(Pessimistic Locking)假设在整个事务过程中,其他线程可能会对数据进行修改,因此在访问数据之前,先获取锁并阻塞其他线程的访问。-
2023-08-12

mysql 乐观锁和悲观锁的具体使用

本文主要介绍了mysql 乐观锁和悲观锁的具体使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
2023-01-08

Java并发编程中的悲观锁和乐观锁机制

这篇文章主要介绍“Java并发编程中的悲观锁和乐观锁机制”,在日常操作中,相信很多人在Java并发编程中的悲观锁和乐观锁机制问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java并发编程中的悲观锁和乐观锁机制
2023-06-02

Java并发编程的悲观锁和乐观锁机制

本篇内容主要讲解“Java并发编程的悲观锁和乐观锁机制”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java并发编程的悲观锁和乐观锁机制”吧!一、资源和加锁1、场景描述多线程并发访问同一个资源问
2023-06-16

MySQL中的乐观锁,悲观锁和MVCC全面解析

前言在数据库的实际使用过程中,我们常常会遇到不希望数据被同时写或者读的情景,例如秒杀场景下,两个请求同时读到系统还有库存1个,然后又先后把库存更新为0,这时候就会出现超卖的情况,这时候货物的实际库存和我们的记录就会对应不上了。 为了解决这种
2022-05-19

mysql 乐观锁和悲观锁的具体使用

目录悲观锁介绍(百科):1如果不采用锁,那么操作方法如下:2使用悲观锁来实现:补充:mysql select…for update的Row Lock与Table Lock乐观锁介绍:使用举例:以MySQL InnoDB为例悲观
2023-01-09

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录