程序员不可能不知道的常见锁策略

前面我们学习过线程不安全问题,我们通过给代码加锁来解决线程不安全问题,在生活中我们也知道有很多种类型的锁,同时在代码的世界当中,也对应着很多类型的锁,今天我们对锁一探究竟!

1. 常见的锁策略

注意: 接下来介绍的锁策略不仅仅是局限于Java.任何和"锁"相关的话题,都可能会涉及到以下内容.这些特性主要是给锁的实现者来参考的.
我们普通的程序猿也需要了解⼀些,对于合理的使用锁也是有很大帮助的.

1.1 乐观锁vs悲观锁

乐观锁: 在执行任务之前预期竞争不激烈,那就可以先不加锁,等后面如果真实发生了锁竞争再加锁

举个例子: 我很喜欢我的女友,在学校时,我们天天在一起,我不担心有冲突别人会占用她(并没有对她上锁),但是偶尔她会和她的好朋友出去,此时,我感觉到有人在和我竞争她,我就加锁,不让她离开我

悲观锁: 在执行任务之前预期竞争非常激烈(表示在执行任务的时候会发生锁冲突),必须先加锁再执行任务

举个例子: 我很喜欢我的女友,为了和她天天在一起,我对她上锁,这样当别人想要和她玩的时候,就会和我竞争,但是我持有锁,别人就会得不到她,显示她一直被我持有,哈哈哈

1.2 重量级锁vs轻量级锁

锁的核心特性"原子性",这样的机制追根溯源是CPU这样的硬件设备提供的.

  • CPU提供了"原子操作指令".
  • 操作系统基于CPU的原子指令,实现了mutex 互斥锁.
  • JVM基于操作系统提供的互斥锁,实现了synchronizedReentrantLock 等关键字和类.
    在这里插入图片描述

轻量级锁: 加锁机制尽可能不使用mutex,而是尽量在用户态代码完成.实在搞不定了,再使用mutex.加锁的过程比较简单,用到的资源比较少,典型就是用户态的一些操作(JAVA 层面就可以完成加锁)

举个例子: 有对象的男同胞,都会遇到的问题,就是和女友出去玩的时候,会等待女友的精心打扮(化妆),轻量级锁就是不停的自旋,一会问一下“宝宝,化好妆了吗”(只是一昧的催促女友,不干别的事情,消耗资源较少),可以第一时间知道女友啥时候化好妆可以出发

重量级锁: 加锁机制重度依赖了OS提供了mutex,加锁的过程比较复杂,用到的资源比较多,典型的就是内核态的一些操作

举个例子: 当女友在化妆的时候,我们不去过问,而是做好自己的事情,准备好出去玩的所有东西(一直在帮忙做事,消耗了很多资源),等待女友的召唤(唤醒),不能第一时间知道女友啥时候化好妆

理解用户态和内核态:
想象去银行办业务.
在窗口外,自己做,这是用户态.用户态的时间成本是比较可控的.
在窗口内,工作人员做,这是内核态.内核态的时间成本是不太可控的. 如果办业务的时候反复和工作人员沟通,还需要重新排队,这时效率是很低的.

乐观锁是能不加锁就不加锁,从而导致他干活少,消耗资源也少,所以可以说乐观锁就是一种轻量级锁
悲观锁是任何时候都加锁,从而导致他干活多,消耗资源也多,所以可以说悲观锁就是一种重量级锁

1.3 自旋锁vs挂起等待锁

自旋锁: 不停的检查锁是否被释放,如果一旦锁被释放就可以直接获取锁资源
挂起等待锁: 阻塞等待,等待到被唤醒

举个例子: 每周末,我要和我对象一起吃饭,我到了她宿舍楼下打电话问她啥时候下来,她说等一会,我就不停的打电话(一直在自旋,不停的检查锁的状态,她下楼了,我会第一时间发现)——>自旋锁,我不打电话了,然后去小亭子坐下来,等待(我就不能第一时间发现她下楼如果她下楼之后就需要喊我一声相当于通知我(唤醒),获取锁资源)——>阻塞:挂起等待锁

优缺点:

  1. 自旋锁:
    纯用户态的操作,可以第一时间获取到锁,
    有自旋次数和时间的限制,通过这个限制可以控制对系统资源的消耗,可以第一时间获取到锁
  2. 挂起等待锁:
    内核态的操作,会生成对应的加锁指令,要等待唤醒,在等待的过程中会释放CPU资源

自旋锁详情请看后续CAS详细介绍

1.4 公平锁vs非公平锁

公平锁: 先来后到,先排队的线程先拿到锁,后排队的线程后拿到锁,JAVA的JUC中有一个类专门实现了公平锁
非公平锁: 大家去抢,谁先抢到是谁的,synchronized是一个非公平锁

注意:

  • 一般情况下,大多数锁都是非公平锁!
  • 操作系统内部的线程调度就可以视为是随机的.如果不做任何额外的限制,锁就是非公平锁.如果要想实现公平锁,就需要依赖额外的数据结构,来记录线程们的先后顺序.
  • 公平锁和非公平锁没有好坏之分,关键还是看适用场景.

举个例子: 现实生活中如果要真正的公平:立法、执法、教育、环境都要发挥作用消耗更大的资源,实现公平锁的过程也是一样,需要用额外的逻辑去管理线程,做到先来后到

1.5.读写锁(readers-writerlock)

多线程之间,数据的读取方之间不会产生线程安全问题,但数据的写入方互相之间以及和读者之间都需要进行互斥。如果两种场景下都用同⼀个锁,就会产生极大的性能损耗。所以读写锁因此而产生。

⼀个线程对于数据的访问,主要存在两种操作:读数据和写数据.

  • 两个线程都只是读⼀个数据,此时并没有线程安全问题.直接并发的读取即可.
  • 两个线程都要写⼀个数据,有线程安全问题.
  • ⼀个线程读另外⼀个线程写,也有线程安全问题.

读写锁就是把读操作和写操作区分对待.Java标准库提供了ReentrantReadWriteLock 类,实现了读写锁.

  • ReentrantReadWriteLock.ReadLock 类表示⼀个读锁.这个对象提供了lock/unlock方法进行加锁解锁.
  • ReentrantReadWriteLock.WriteLock 类表示⼀个写锁.这个对象也提供了lock/unlock方法进行加锁解锁.

其中,

  • 读加锁和读加锁之间,不互斥.
  • 写加锁和写加锁之间,互斥.
  • 读加锁和写加锁之间,互斥.

注意,只要是涉及到"互斥",就会产⽣线程的挂起等待.⼀旦线程挂起,再次被唤醒就不知道隔了多久了.因此尽可能减少"互斥"的机会,就是提高效率的重要途径.
适用场景:
读写锁特别适合于"频繁读,不频繁写"的场景中.(这样的场景其实也是非常广泛存在的).

举个例子: 大学生必备学习通,老师会经常上课点名(读操作),发布学习资料(写操作),同学们看详细资料(读操作),读操作会涉及很多次,但是写操作偶尔几周一次,所以很适合读写锁

1.6可重入锁VS不可重入锁

可重入锁: 对一把锁可以连续加多次,多次加锁也要多次解锁,不造成死锁
不可重入锁: 对一把锁可以连续加多次,造成死锁

2. 相关面试题

2.1 你是怎么理解乐观锁和悲观锁的,具体怎么实现呢?

  1. 悲观锁认为多个线程访问同⼀个共享变量冲突的概率较大,会在每次访问共享变量之前都去真正加锁.
  2. 乐观锁认为多个线程访问同⼀个共享变量冲突的概率不大.并不会真的加锁,而是直接尝试访问数据.在访问的同时识别当前的数据是否出现访问冲突.
  3. 悲观锁的实现就是先加锁(比如借助操作系统提供的mutex),获取到锁再操作数据.获取不到锁就等待.
  4. 乐观锁的实现可以引入⼀个版本号.借助版本号识别出当前的数据访问是否冲突.

2.2 介绍下读写锁?

  1. 读写锁就是把读操作和写操作分别进行加锁.
  2. 读锁和读锁之间不互斥.
  3. 写锁和写锁之间互斥.
  4. 写锁和读锁之间互斥.
  5. 读写锁最主要用在"频繁读,不频繁写"的场景中

2.3 什么是自旋锁,为什么要使用自旋锁策略呢,缺点是什么?

  1. 如果获取锁失败,立即再尝试获取锁,无限循环,直到获取到锁为止.第⼀次获取锁失败,第二次的尝试会在极短的时间内到来.⼀旦锁被其他线程释放,就能第⼀时间获取到锁.

相比于挂起等待锁,

  1. 优点:没有放弃CPU资源,⼀旦锁被释放就能第⼀时间获取到锁,更高效.在锁持有时间比较短的场景下非常有用.
  2. 缺点:如果锁的持有时间较长,就会浪费CPU资源.

2.4 synchronized 是可重入锁么?

是可重入锁.
可重入锁指的就是连续两次加锁不会导致死锁.
实现的方式是在锁中记录该锁持有的线程身份,以及⼀个计数器(记录加锁次数).如果发现当前加锁的线程就是持有锁的线程,则直接计数自增.

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

智启未来,AI筑梦科技新星”------华清远见成都中心2025冬令营圆满结束

2025年1月11日-16日,华清远见成都中心为期6天的“智启未来,AI筑梦科技新星”2025冬令营活动圆满结束。此次活动吸引了众多对人工智能和无人驾驶技术充满热情的学生参与,共同开启了一段点燃科技梦想的精彩旅程。 报道接待 以AI无人驾驶小车为核…

Debezium日常分享系列之:对于从Oracle数据库进行快照的性能优化

Debezium日常分享系列之:对于从Oracle数据库进行快照的性能优化 源数据库Kafka Connect监控测试结果 源数据库 Oracle 19c,本地,CDB数据库主机的I/O带宽为6 GB/s,由此主机上运行的所有数据库共享临时表空间由42个文件组成&#x…

RabbitMQ--延迟队列

(一)延迟队列 1.概念 延迟队列是一种特殊的队列,消息被发送后,消费者并不会立刻拿到消息,而是等待一段时间后,消费者才可以从这个队列中拿到消息进行消费 2.应用场景 延迟队列的应用场景很多,…

3DsMax设置中文界面

按键盘上的“Win”键,直接输入3dsmax,选择Simplified Chinese打开,之后就都是中文了

opencv在图片上添加中文汉字(c++以及python)

opencv在图片上添加中文汉字(c以及python)_c opencv绘制中文 知乎-CSDN博客 环境: ubuntu18.04 desktopopencv 3.4.15 opencv是不支持中文的。 这里C代码是采用替换原图的像素点来实现的,实现之前我们先了解一下汉字点阵字库。…

线程同步与Mutex

梦想是逃离世界… 文章目录 一、什么是线程同步?二、线程同步机制三、互斥锁(Mutex)四、loock 和 unlock五、Mutex的四种类型 一、什么是线程同步? 线程同步(Thread Synchronization)是多线程编程中的一个重要概念,它…

基于SpringBoot和PostGIS的全球首都信息管理设计与实现

目录 前言 一、首都空间表的设计 1、三张空间表的结构 二、SpringBoot后台管理的设计与实现 1、模型层的实现 2、业务层及控制层实现 三、前端的实现与成果可视化 1、新增数据的保存 2、首都的实际管理成果 3、全球首都信息 四、总结 前言 首都,一个国家的…

计算机网络 (50)两类密码体制

前言 计算机网络中的两类密码体制主要包括对称密钥密码体制(也称为私钥密码体制、对称密码体制)和公钥密码体制(也称为非对称密码体制、公开密钥加密技术)。 一、对称密钥密码体制 定义: 对称密钥密码体制是一种传…

【数据结构篇】顺序表 超详细

目录 一.顺序表的定义 1.顺序表的概念及结构 1.1线性表 2.顺序表的分类 2.1静态顺序表 2.2动态顺序表 二.动态顺序表的实现 1.准备工作和注意事项 2.顺序表的基本接口: 2.0 创建一个顺序表 2.1 顺序表的初始化 2.2 顺序表的销毁 2.3 顺序表的打印 3.顺序…

C 语言雏启:擘画代码乾坤,谛观编程奥宇之初瞰

大家好啊,我是小象٩(๑ω๑)۶ 我的博客:Xiao Xiangζั͡ޓއއ 很高兴见到大家,希望能够和大家一起交流学习,共同进步。* 这一课主要是让大家初步了解C语言,了解我们的开发环境,main函数,库…

根据 Web 服务器端的架构相关知识,将PHP改JAVA重构企业网站系统

目录 案例 【题目】 【问题 1】(7 分) 【问题 2】(8 分) 【问题 3】(10 分) 答案 【问题 1】解析 【问题 2】解析 【问题 3】解析 相关推荐 案例 阅读以下关于应用服务器的叙述,在答题纸上回答问题 1 至问题 3。 【题目】 某电子产品制造公司&#xff0c…

多选multiple下拉框el-select回显问题(只显示后端返回id)

首先保证v-model的值对应options数据源里面的id <el-form-item prop"subclass" label"分类" ><el-select v-model"formData.subclass" multiple placeholder"请选择" clearable :disabled"!!formData.id"><e…

java快速导出word文档

点关注不迷路&#xff0c;欢迎再访&#xff01; 精简博客内容&#xff0c;尽量已行业术语来分享。 努力做到对每一位认可自己的读者负责。 帮助别人的同时更是丰富自己的良机。 文章目录 前言一.添加 Apache POI 依赖二.填充文档内容三.导出文档效果测试 前言 在 Java 应用程序…

《MambaIR:一种基于状态空间模型的简单图像修复基线方法》学习笔记

paper&#xff1a;2402.15648 目录 摘要 一、引言 1、模型性能的提升依赖于网络感受野的扩大&#xff1a; 2、全局感受野和高效计算之间存在固有矛盾&#xff1a; 3、改进版 Mamba的巨大潜力 4、Mamba 在图像修复任务中仍面临以下挑战&#xff1a; 5、方法 6、主要贡献…

ngnix上传小文件成功,大文件报错

ngnix错误日志 "/var/tmp/nginx/client//0000001299" failed (2: No such file or directory), client: 10.188.141.160, server: 127.0.0.1, request: "POST /fts/sys/common/biUpload HTTP/1.1", host: "10.20.166.179", referrer: "http…

Word表格批量提取数据到Excel,批量提取,我爱excel

Word表格批量提取数据到Excel&#xff0c;Word导出到Excel - 我爱Excel助你高效办公 在日常办公中&#xff0c;Word表格常常用于记录和整理数据&#xff0c;但将这些数据从Word提取到Excel&#xff0c;特别是当涉及多个文件时&#xff0c;常常让人头疼。如果你经常需要将多个W…

【Zookeeper】Windows下安装Zookeeper(图文记录详细步骤,手把手包安装成功)

【Zookeeper】Windows下安装Zookeeper Zookeeper简介一、下载Zookeeper安装包1.1、官网下载Zookeeper1.2、网盘下载Zookeeper 二、解压Zookeeper安装包到指定目录三、Zookeeper安装目录下创建文件夹四、进入config目录五、复制zoo_sample.cfg文件&#xff0c;改名为zoo.cfg六、…

JDK长期支持版本(LTS)

https://blogs.oracle.com/java/post/the-arrival-of-java-23 jdk长期支持版本&#xff08;LTS&#xff09;&#xff1a;JDK 8、11、17、21&#xff1a;

深度学习J3周:RNN-心脏病预测

&#x1f368; 本文为&#x1f517;365天深度学习训练营中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 要求&#xff1a; 1.本地读取并加载数据 2.了解循环神经网络&#xff08;RNN&#xff09;的构建过程 3.测试集accuracy到达87% 拔高&#xff1a; 测试机a…

Linux C\C++方式下的文件I/O编程

【图书推荐】《Linux C与C一线开发实践&#xff08;第2版&#xff09;》_linux c与c一线开发实践pdf-CSDN博客 《Linux C与C一线开发实践&#xff08;第2版&#xff09;&#xff08;Linux技术丛书&#xff09;》(朱文伟&#xff0c;李建英)【摘要 书评 试读】- 京东图书 Lin…