高级java每日一道面试题-2024年7月29日-并发篇-什么时候用乐观锁,什么时候用悲观锁?

面试官: 什么时候用乐观锁,什么时候用悲观锁?

我回答:

乐观锁和悲观锁是两种常用的并发控制策略,它们在多线程环境下用于保护共享资源免受并发修改的问题。下面我们将详细讨论这两种锁的使用场景和优缺点,以便你在实际开发中能够根据具体情况做出合适的选择。

悲观锁

悲观锁(Pessimistic Locking)假设最坏的情况,即认为数据非常有可能会发生冲突,所以在数据被读取的时候就开始加锁,直到修改完毕释放锁。对共享资源的访问会产生冲突,因此默认认为每次访问都会发生冲突,需要加锁保证独占访问。

特点
  • 加锁时机:在开始操作数据之前加锁。
  • 解锁时机:在完成数据操作后解锁。
  • 适用场景
    • 数据更新频繁,竞争激烈。
    • 数据一致性要求非常高。
    • 对性能要求不高,可以接受较高的锁等待时间。
优点
  • 确保了数据的一致性。
  • 在高竞争的情况下,可以有效地避免数据冲突。
缺点
  • 锁的竞争可能导致线程等待时间较长,降低系统的整体吞吐量。
  • 过度锁定可能导致线程饥饿。

实现方式:

  • 可以使用synchronized关键字或java.util.concurrent.locks包下的Lock接口的具体实现(如ReentrantLock)来实现。

乐观锁

乐观锁(Optimistic Locking)则假设最乐观的情况,即认为数据不太可能发生冲突,所以在数据被读取时不加锁,只有在更新数据的时候才判断数据是否被其他线程修改过。

在读取数据时,每个线程会获得一个标识符(如版本号或时间戳)。在提交修改之前,会比较当前标识符与之前读取的标识符是否相等,如果相等则提交成功,否则说明数据已被其他线程修改,需要进行冲突处理。

特点
  • 加锁时机:在更新数据时才进行版本号比较或加锁。
  • 解锁时机:如果数据版本匹配,则更新数据并释放锁;如果不匹配,则放弃本次更新。
  • 适用场景
    • 数据更新不频繁,竞争不激烈。
    • 数据一致性要求相对较低。
    • 对性能要求较高,尽量减少锁的使用。
优点
  • 减少了锁的使用,提高了系统的并发能力。
  • 适用于读多写少的场景。
缺点
  • 在高并发的情况下,可能会出现多次尝试更新数据的情况。
  • 如果数据冲突频繁发生,性能优势会减弱。
实现方式:
  • 通常使用版本号或时间戳来实现。
  • 可以在数据库中添加一个额外的字段作为标识符,并在更新操作时进行比较。
  • 在Java中,可以通过java.util.concurrent.atomic包下的原子类(如AtomicIntegerAtomicLongAtomicStampedReference等)利用CAS(Compare and Swap)算法来实现乐观锁。

选择时机

何时使用悲观锁?
  • 高并发更新:如果一个资源被频繁地并发修改,悲观锁可以确保数据的一致性。
  • 数据竞争激烈:当多个线程试图修改同一资源时,悲观锁可以有效防止数据冲突。
  • 严格的数据一致性要求:对于金融交易、数据库事务等场景,悲观锁可以提供更强的一致性保证。
  • 适用于写操作频繁的场景。
  • 能够确保数据一致性和线程安全。
何时使用乐观锁?
  • 低并发更新:如果资源的并发修改较少,使用乐观锁可以减少锁的竞争。
  • 读多写少:当大部分操作是读取而非修改时,乐观锁可以提高并发性能。
  • 性能敏感的应用:对于需要高性能的应用程序,乐观锁可以减少锁带来的性能开销。

总结

  • 悲观锁 适用于数据竞争激烈的场景,能够提供强一致性,但可能导致较多的线程等待。
  • 乐观锁 适用于读多写少的场景,能够提供更高的并发性能,但可能需要多次尝试才能成功更新数据。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/51435.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

快速写一个Makefile

本文主要展示Makefile的基本要素和示例&#xff0c;让读者可以快速写出一个实用的Makefile。 简要说明 Makefile&#xff0c;GNU make命令工具。 书写格式 <target> : <prerequisites> [tab] <commands> <target> 文件名或某操作的名字&#xff0…

uniapp开发精选短视频视频小程序实战笔记20240725,实现顶部轮播图和热门短剧

创建项目 创建项目,叫video_app。 在pages.json里面修改一下标题: 新建search搜索页面和me我的页面。 此时界面预览效果如下: 引入静态资源 主要是static里面的内容,全部复制过来。 配置底部导航栏 pages.json,放到顶层,和全部样式同级: "tabBar&quo…

详细分析 Sql Server查询卡顿的排查方向

目录 前言1. 问题所示2. 原理分析2.1 缺乏索引2.2 表碎片2.3 查询计划缓存2.4 锁和阻塞 3. 总结 前言 本篇为理论知识的分析以及对症下药&#xff0c;前阵子发生过Bug&#xff0c;后通过迁移服务器以及数据库最终才解决问题&#xff0c;但是细想当时可能是因为碎片或者缓存的概…

WEBKIT 通过JavaScript 调用本地,硬件未来之窗OS硬件APP

以酒店为例我们需要调用shen份证读取&#xff0c;采集人脸&#xff0c;门锁写房卡&#xff0c;如何通过浏览器调用 1.通过本地http服务 2.通过webkit模式 这里说政务单位模式的集成 由于篇幅问题&#xff0c;怎么集成webkit就不说了 一、webkkit加载交互本地代码 browser.…

百日筑基第三十四天-JAVA中的强/软/弱/虚引用

百日筑基第三十四天-JAVA中的强/软/弱/虚引用 Java对象的引用被划分为4种级别&#xff0c;分别为强引用、软引用、弱引用以及虚引用。帮助程序更加灵活地控制对象的生命周期和JVM进行垃圾回收。 强引用 强引用是最普遍的引用&#xff0c;一般把一个对象赋给一个引用变量&…

23、Python之面向对象:实例属性、类属性,傻傻分不清楚

引言 在上一篇文章中&#xff0c;我们初步介绍了Python面向对象中类定义的语法&#xff0c;顺带介绍了关于面向对象的系统工程中&#xff0c;所涉及的OOA与OOD。 其实&#xff0c;简单来说&#xff0c;类的定义其实就是面向对象的“封装”特性的体现。我们将分析、设计得到的…

BLE自适应跳频算法详解

前言 &#xff08;1&#xff09;自适应跳频算法是相当的简单&#xff0c;小学生都能够看懂&#xff0c;而且网上已经有相当多的关于自适应跳频算法的介绍。既然如此&#xff0c;为什么我还要写这样一篇博客呢&#xff1f; &#xff08;2&#xff09;原因很简单&#xff0c;我发…

内网横向——利用WMI进行内网横向

文章目录 一、WMI介绍二、常规利用方法三、常见利用工具3.1 wmiexec3.2 Invoke-WmiCommand 四、WMI事件订阅的利用4.1 手动实现4.2 Sharp-WMIEvent 网络拓扑&#xff1a; 攻击机kali IP&#xff1a;192.168.111.0 跳板机win7 IP&#xff1a;192.168.111.128&#xff0c;192.168…

业务记录:处理动态表头的CSV/EXCEL文件

业务描述&#xff1a;传入一个动态表头的CSV文件&#xff0c;解析CSV&#xff0c;并保存入库。 CSV文件的表头是不确定的&#xff0c;即顺序和字段个数不确定&#xff0c;以及表头是中文字段。 例如&#xff1a; 为了顺利解析CSV文件&#xff0c;前端需要传入对应的字段名和顺…

.NET Core 命令大全

目录 1. 基本命令 2. 项目管理命令 3. 测试和调试命令 4. 包管理命令 5. 工具和扩展命令 结语 .NET Core 是一个跨平台、开源的开发平台&#xff0c;用于构建各种应用程序。为了方便开发者进行操作&#xff0c;.NET Core 提供了一系列的命令行工具。这篇文章将详细介绍这…

如何将anaconda的根环境复制到新环境

anaconda将根环境复制到新环境 在Anaconda中&#xff0c;您可以使用conda create命令来复制根环境到一个新的环境。以下是一个命令示例&#xff1a; conda create --name new_env --clone root 这里new_env是新环境的名字&#xff0c;您可以根据需要将其更改为您想要的名字。…

前端数据处理

数据处理 多字段&#xff08;数字类型&#xff09;排序 let arr [{name: jim, math: 85, english: 66, chinese: 36},{name: tom, math: 78, english: 70, chinese: 87},{name: lilei, math: 78, english: 89, chinese: 36},{name: alice, math: 90, english: 20, chinese: …

docker安装mysql遇到的问题

1、3306端口被占用 Error starting userland proxy: listen tcp4 0.0.0.0:3306: bind: address already https://blog.csdn.net/qq_42680327/article/details/136851627 2、mysql已经被占用 docker: Error response from daemon: Conflict. The container name “/mysql“ is…

使用SpringBoot集成Shardingjdbc介绍、应用场景和示例代码

概述 Spring Boot集成Sharding JDBC可以帮助实现MySQL数据库的分库分表操作&#xff0c;使得应用能够轻松处理大规模数据和高并发场景。Sharding JDBC通过透明的分库分表策略&#xff0c;将数据分布到多个数据库实例和数据表中&#xff0c;从而提高数据库的扩展性和性能。 应…

axure制作切换栏--动态面板的应用

先看下效果&#xff1a;点击上面的切换栏 切换到西游记栏目&#xff1a; 切换到水浒传栏目&#xff1a; 上述两个图片比对可以发现&#xff0c;在点击切换栏的时候&#xff0c;里面的内容以及切换栏的下面蓝色横线也会发生对应的变化。这里涉及到两个地方的变化&#xff0c;就…

Golang 知识结构图

总结Go的入门知识结构&#xff0c;如下图所示&#xff1a;

关于map的内存和时间复杂度内存占用

关于map的内存和时间复杂度&#xff08;map尽量别碰暴力遍历&#xff09; 内存占用&#xff1a; map中每个元素包含一个键和一个值。键和值的类型可以是任意可比较的数据类型。 内存占用取决于键和值的大小以及map中元素的数量。 对于固定大小的键和值类型&#xff0c;map的内…

图形/视图结构的三个坐标系

图形/视图结构的三个坐标系分别为视图结构系物理结构系&#xff0c;场景坐标系&#xff0c;图形项坐标系。 本文记录实践三个坐标系及视图与场景坐标转换&#xff0c;通过事件槽来显示出来的过程。 自定义1个View视图组件&#xff0c;其中扩展了鼠标点击、鼠标移动的事件&…

详细介绍仿函数

仿函数&#xff08;Functor&#xff09;是C中的一种可调用对象&#xff08;Callable Object&#xff09;&#xff0c;也是一种重载了函数调用运算符&#xff08;operator()&#xff09;的类或结构体。 仿函数可以像函数一样被调用&#xff0c;可以带参数&#xff0c;可以返回值…

Golang | Leetcode Golang题解之第297题二叉树的序列化与反序列化

题目&#xff1a; 题解&#xff1a; type Codec struct{}func Constructor() (_ Codec) {return }func (c Codec) serialize(root *TreeNode) string {if root nil {return "X"}left : "(" c.serialize(root.Left) ")"right : "("…