java的各种锁

我们先来看看有什么锁

一、java锁

1、乐观锁

                            
乐观锁 是一种乐观思想 ,假定当前环境是读多写少,遇到并发写的概率比较低,读数
据时认为别的线程不会正在进行修改(所以没有上锁)。写数据时,判断当前 与期望
值是否相同,如果相同则进行更新(更新期间加锁,保证是原子性的)。
Java中的 乐观锁 : CAS ,比较并替换,比较当前值(主内存中的值),与预期值(当前
线程中的值,主内存中值的一份拷贝)是否一样,一样则更新,否则继续进行CAS操
作。
如上图所示,可以同时进行读操作,读的时候其他线程不能进行写操作。

2、悲观锁

悲观锁 是一种悲观思想 ,即认为写多读少,遇到并发写的可能性高,每次去拿数据的
时候都认为其他线程会修改,所以每次读写数据都会认为其他线程会修改,所以每次
读写数据时都会上锁。其他线程想要读写这个数据时,会被这个线程block,直到这
个线程释放锁然后其他线程获取到锁。
Java中的 悲观锁 : synchronized 修饰的方法和方法块、 ReentrantLock 。
如上图所示,只能有一个线程进行读操作或者写操作,其他线程的读写操作均不能进
行。

3、自旋锁

自旋锁 是一种技术: 为了让线程等待,我们只须让线程执行一个忙循环(自旋)。
现在绝大多数的个人电脑和服务器都是多路(核)处理器系统,如果物理机器有一个
以上的处理器或者处理器核心,能让两个或以上的线程同时并行执行,就可以让后面
请求锁的那个线程“稍等一会”,但不放弃处理器的执行时间,看看持有锁的线程是
否很快就会释放锁。
自旋锁 的优点: 避免了线程切换的开销。挂起线程和恢复线程的操作都需要转入内核
态中完成,这些操作给Java虚拟机的并发性能带来了很大的压力。
自旋锁 的缺点: 占用处理器的时间,如果占用的时间很长,会白白消耗处理器资源,
而不会做任何有价值的工作,带来性能的浪费。因此自旋等待的时间必须有一定的限
度,如果自旋超过了限定的次数仍然没有成功获得锁,就应当使用传统的方式去挂起
线程。
自旋 次数默认值: 10次,可以使用参数-XX:PreBlockSpin来自行更改。 自适应 自旋 : 自适应意味着自旋的时间不再是固定的,而是由前一次在同一个锁上的
自旋时间及锁的拥有者的状态来决定的。有了自适应自旋,随着程序运行时间的增长
及性能监控信息的不断完善,虚拟机对程序锁的状态预测就会越来越精准。
Java中的 自旋锁 : CAS操作中的比较操作失败后的自旋等待。

4、可重入锁(递归锁)

可重入锁 是一种技术: 任意线程在获取到锁之后能够再次获取该锁而不会被锁所阻
塞。
可重入锁 的原理: 通过组合自定义同步器来实现锁的获取与释放。
再次获取锁:识别获取锁的线程是否为当前占据锁的线程,如果是,则再
次成功获取。获取锁后,进行计数自增,
释放锁:释放锁时,进行计数自减。
Java中的 可重入锁 : ReentrantLock、synchronized修饰的方法或代码段。
可重入锁 的作用: 避免死锁。
面试题1: 可重入锁如果加了两把,但是只释放了一把会出现什么问题?
答:程序卡死,线程不能出来,也就是说我们申请了几把锁,就需要释放几把锁。
面试题2: 如果只加了一把锁,释放两次会出现什么问题? 答:会报错,java.lang.IllegalMonitorStateException。

5、读写锁

读写锁 是一种技术: 通过 ReentrantReadWriteLock 类来实现。为了提高性能, Java
提供了读写锁,在读的地方使用读锁,在写的地方使用写锁,灵活控制,如果没有写
锁的情况下,读是无阻塞的,在一定程度上提高了程序的执行效率。 读写锁分为读锁
和写锁,多个读锁不互斥,读锁与写锁互斥,这是由 jvm 自己控制的。
读锁: 允许多个线程获取读锁,同时访问同一个资源。
                     
写锁: 只允许一个线程获取写锁,不允许同时访问同一个资源。 如何使用:
/*** 创建一个读写锁 * 它是一个读写融为一体的锁,在使用的时候,需要转换 */
private ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
获取读锁和释放读锁
// 获取读锁 rwLock.readLock().lock();
// 释放读锁 rwLock.readLock().unlock();
获取写锁和释放写锁
// 创建一个写锁 rwLock.writeLock().lock();
// 写锁 释放 rwLock.writeLock().unlock();
Java中的读写锁: ReentrantReadWriteLock

6、公平锁

公平锁 是一种思想: 多个线程按照申请锁的顺序来获取锁。在并发环境中,每个线程
会先查看此锁维护的等待队列,如果当前等待队列为空,则占有锁,如果等待队列不
为空,则加入到等待队列的末尾,按照FIFO的原则从队列中拿到线程,然后占有锁。

7、非公平锁

非公平锁 是一种思想: 线程尝试获取锁,如果获取不到,则再采用公平锁的方式。多
个线程获取锁的顺序,不是按照先到先得的顺序,有可能后申请锁的线程比先申请的
线程优先获取锁。
优点: 非公平锁的性能高于公平锁。
缺点: 有可能造成线程饥饿(某个线程很长一段时间获取不到锁)
Java中的非公平锁: synchronized是非公平锁,ReentrantLock通过构造函数指定
该锁是公平的还是非公平的,默认是非公平的。

8、共享锁

共享锁 是一种思想: 可以有多个线程获取读锁,以共享的方式持有锁。和乐观锁、读
写锁同义。
Java中用到的共享锁: ReentrantReadWriteLock 。

9、独占锁

独占锁 是一种思想: 只能有一个线程获取锁,以独占的方式持有锁。和悲观锁、互斥
锁同义。
Java中用到的独占锁: synchronized,ReentrantLock

10、重量级锁

重量级锁是一种称谓: synchronized 是通过对象内部的一个叫做监视器锁
( monitor )来实现的,监视器锁本身依赖底层的操作系统的 Mutex Lock 来实现。操
作系统实现线程的切换需要从用户态切换到核心态,成本非常高。这种依赖于操作系
统 Mutex Lock 来实现的锁称为重量级锁。为了优化 synchonized ,引入了 轻量级锁 ,
偏向锁 。
Java中的重量级锁: synchronized

11、轻量级锁

轻量级锁 是JDK6时加入的一种锁优化机制: 轻量级锁是在无竞争的情况下使用CAS操
作去消除同步使用的互斥量。轻量级是相对于使用操作系统互斥量来实现的重量级锁
而言的。轻量级锁在没有多线程竞争的前提下,减少传统的重量级锁使用操作系统互
斥量产生的性能消耗。如果出现两条以上的线程争用同一个锁的情况,那轻量级锁将
不会有效,必须膨胀为重量级锁。
优点: 如果没有竞争,通过CAS操作成功避免了使用互斥量的开销。
缺点: 如果存在竞争,除了互斥量本身的开销外,还额外产生了CAS操作的开销,因
此在有竞争的情况下,轻量级锁比传统的重量级锁更慢。

12、偏向锁

偏向锁 是JDK6时加入的一种锁优化机制: 在无竞争的情况下把整个同步都消除掉,
连CAS操作都不去做了。偏是指偏心,它的意思是这个锁会偏向于第一个获得它的线
程,如果在接下来的执行过程中,该锁一直没有被其他的线程获取,则持有偏向锁的
线程将永远不需要再进行同步。持有偏向锁的线程以后每次进入这个锁相关的同步块 时,虚拟机都可以不再进行任何同步操作(例如加锁、解锁及对Mark Word的更新
操作等)。
优点: 把整个同步都消除掉,连CAS操作都不去做了,优于轻量级锁。
缺点: 如果程序中大多数的锁都总是被多个不同的线程访问,那偏向锁就是多余的。

13、分段锁

分段锁 是一种机制: 最好的例子来说明分段锁是ConcurrentHashMap。
ConcurrentHashMap原理: 它内部细分了若干个小的 HashMap,称之为段
(Segment)。 默认情况下一个 ConcurrentHashMap 被进一步细分为 16 个段,既
就是锁的并发度。如果需要在 ConcurrentHashMap 添加一项key-value,并不是将
整个 HashMap 加锁,而是首先根据 hashcode 得到该key-value应该存放在哪个段
中,然后对该段加锁,并完成 put 操作。在多线程环境中,如果多个线程同时进行 put操作,只要被加入的key-value不存放在同一个段中,则线程间可以做到真正的并
行。
线程安全: ConcurrentHashMap 是一个 Segment 数组, Segment 通过继承
ReentrantLock 来进行加锁,所以每次需要加锁的操作锁住的是一个 segment,这
样只要保证每个 Segment 是线程安全的,也就实现了全局的线程安全

14、互斥锁

               
互斥锁与悲观锁、独占锁同义,表示某个资源只能被一个线程访问,其他线程不能访
问。
读-读互斥
读-写互斥
写-读互斥 写-写互斥
Java中的同步锁: synchronized

15、同步锁

同步锁与互斥锁同义,表示并发执行的多个线程,在同一时间内只允许一个线程访问
共享数据。
Java中的同步锁: synchronized

16、死锁

死锁是一种现象: 如线程A持有资源x,线程B持有资源y,线程A等待线程B释放资源
y,线程B等待线程A释放资源x,两个线程都不释放自己持有的资源,则两个线程都获
取不到对方的资源,就会造成死锁。
Java中的死锁不能自行打破,所以线程死锁后,线程不能进行响应。所以一定要注意
程序的并发场景,避免造成死锁。

17、锁粗化

                    
锁粗化 是一种优化技术: 如果一系列的连续操作都对同一个对象反复加锁和解锁,甚
至加锁操作都是出现在循环体体之中,就算真的没有线程竞争,频繁地进行互斥同步
操作将会导致不必要的性能损耗,所以就采取了一种方案:把加锁的范围扩展(粗
化)到整个操作序列的外部,这样加锁解锁的频率就会大大降低,从而减少了性能损
耗。

18、锁消除

锁消除 是一种优化技术: 就是把锁干掉。当Java虚拟机运行时发现有些共享数据不会
被线程竞争时就可以进行锁消除。
那如何判断共享数据不会被线程竞争?
利用 逃逸分析技术 :分析对象的作用域,如果对象在A方法中定义后,被作为参数传递
到B方法中,则称为方法逃逸;如果被其他线程访问,则称为线程逃逸。
在堆上的某个数据不会逃逸出去被其他线程访问到,就可以把它当作栈上数据对待,
认为它是线程私有的,同步加锁就不需要了。

19、synchronized

synchronized 是Java中的关键字:用来修饰方法、对象实例。属于独占锁、悲观锁、
可重入锁、非公平锁。
1.作用于实例方法时,锁住的是对象的实例(this);
2.当作用于静态方法时,锁住的是 Class类,相当于类的一个全局锁,会锁
所有调用该方法的线程;
3.synchronized 作用于一个非 NULL的对象实例时,锁住的是所有以该对
象为锁的代码块。 它有多个队列,当多个线程一起访问某个对象监视器的时
候,对象监视器会将这些线程存储在不同的容器中。
每个对象都有个 monitor 对象, 加锁就是在竞争 monitor 对象,代码块加锁是在代
码块前后分别加上 monitorenter 和 monitorexit 指令来实现的,方法加锁是通过一
个标记位来判断的。

20、Lock和synchronized的区别

Lock : 是Java中的接口,可重入锁、悲观锁、独占锁、互斥锁、同步锁。
1.Lock需要手动获取锁和释放锁。就好比自动挡和手动挡的区别
2.Lock 是一个接口,而 synchronized 是 Java 中的关键字,
synchronized 是内置的语言实现。
3.synchronized 在发生异常时,会自动释放线程占有的锁,因此不会导致
死锁现象发生;而 Lock 在发生异常时,如果没有主动通过 unLock()去释放
锁,则很可能造成死锁现象,因此使用 Lock 时需要在 finally 块中释放锁。 4.Lock 可以让等待锁的线程响应中断,而 synchronized 却不行,使用
synchronized 时,等待的线程会一直等待下去,不能够响应中断。
5.通过 Lock 可以知道有没有成功获取锁,而 synchronized 却无法办到。
6.Lock 可以通过实现读写锁提高多个线程进行读操作的效率。
synchronized的优势:
足够清晰简单,只需要基础的同步功能时,用synchronized。
Lock应该确保在finally块中释放锁。如果使用synchronized,JVM确保即
使出现异常,锁也能被自动释放。
使用Lock时,Java虚拟机很难得知哪些锁对象是由特定线程锁持有的。

21、ReentrantLock 和synchronized的区别

ReentrantLock 是Java中的类 : 继承了Lock类,可重入锁、悲观锁、独占锁、互斥
锁、同步锁。
划重点
相同点:
1.主要解决共享变量如何安全访问的问题
2.都是可重入锁,也叫做递归锁,同一线程可以多次获得同一个锁,
3.保证了线程安全的两大特性:可见性、原子性。
不同点:
1.ReentrantLock 就像手动汽车,需要显示的调用lock和unlock方法, synchronized 隐式获得释放锁。
2.ReentrantLock 可响应中断, synchronized 是不可以响应中断的, ReentrantLock 为处理锁的不可用性提供了更高的灵活性
3.ReentrantLock 是 API 级别的, synchronized 是 JVM 级别的
4.ReentrantLock 可以实现公平锁、非公平锁,默认非公平锁, synchronized 是非公平锁,且不可更改。
5.ReentrantLock 通过 Condition 可以绑定多个条件

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

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

相关文章

C语言经典例题-20

1.判断字母 题目描述 从键盘任意输入一个字符,编程判断是否是字母(包括大小写)。 输入描述: 多组输入,每行输入包括一个字符。 输出描述: 针对每行输入,输出该字符是字母(YES)或不是&#xf…

使用Python实现超参数调优

超参数调优是机器学习模型调优过程中的重要步骤,它可以帮助我们找到最佳的超参数组合,从而提高模型的性能和泛化能力。在本文中,我们将介绍超参数调优的基本原理和常见的调优方法,并使用Python来实现这些方法。 什么是超参数&…

算法打卡day48|动态规划篇16| Leetcode 583. 两个字符串的删除操作、72. 编辑距离

算法题 Leetcode 583. 两个字符串的删除操作 题目链接:583. 两个字符串的删除操作 大佬视频讲解:583. 两个字符串的删除操作视频讲解 个人思路 本题和115.不同的子序列相比,变为了两个字符串都可以删除,整体思路是不变的,依旧…

vue3中web前端JS动画案例(二)多物体运动-多值运动

<script setup> import { ref, onMounted, watch } from vue // ----------------------- 01 js 动画介绍--------------------- // 1、匀速运动 // 2、缓动运动&#xff08;常见&#xff09; // 3、透明度运动 // 4、多物体运动 // 5、多值动画// 6、自己的动画框架 // …

在PostgreSQL中如何实现递归查询,例如使用WITH RECURSIVE构建层次结构数据?

文章目录 解决方案使用WITH RECURSIVE进行递归查询示例代码 总结 在PostgreSQL中&#xff0c;递归查询是一种非常强大的工具&#xff0c;它可以用来查询具有层次结构或树形结构的数据。例如&#xff0c;你可能会在员工-经理关系、目录结构或组织结构图中遇到这样的数据。为了处…

MybatisPlus 逻辑删除

目录 一、配置MybatisPlus 二、添加注解 三、调用MybatisPlus的删除方法 四、测试结果 一、配置MybatisPlus # mybatis-plus mybatis-plus:# 全局配置global-config:db-config:# 全局逻辑删除的字段名logic-delete-field: deleted# 逻辑已删除值(默认为 d)logic-delete-va…

为什么科拓停车选择OceanBase来构建智慧停车SaaS应用

本文来自OceanBase的客户——拓客停车的实践分享 科拓停车简介与业务背景 作为智慧停车行业的佼佼者&#xff0c;科拓停车致力于提供全方位的智慧停车解决方案。服务涵盖车场运营管理、互联网智慧停车平台以及停车场增值服务等。通过不断研发创新&#xff0c;打造出了多样化的…

Linux的主机状态

查看系统资源占用 可以通过top命令查看CPU、内存使用情况&#xff0c;类似Windows的任务管理器 默认每5秒刷新一次&#xff0c;语法&#xff1a;直接输入top即可&#xff0c;按q或ctrl c退出 第一行&#xff1a; top&#xff1a;命令名称&#xff0c;14:39:58&#xf…

js aes加密 md5摘要 base64编码 ras加密

crypto-js npm install crypto-js主要用来处理&#xff1a; md5&#xff0c; AES, Base64 md5 摘要 const CryptoJS require(crypto-js);function md5_test() {// 字符串入参console.log(CryptoJS.MD5(qwwqww).toString());// WordArray 入参const wordArray CryptoJS.enc…

LeetCode 每日一题 2024/4/15-2024/4/21

记录了初步解题思路 以及本地实现代码&#xff1b;并不一定为最优 也希望大家能一起探讨 一起进步 目录 4/15 706. 设计哈希映射4/16 924. 尽量减少恶意软件的传播4/17 928. 尽量减少恶意软件的传播 II4/18 2007. 从双倍数组中还原原数组4/19 1883. 准时抵达会议现场的最小跳过…

Sentinel 流控注解使用

大概原理&#xff1a;通过反射解析注解 SentinelResource信息完成调用&#xff0c;处理方法&#xff0c;类似AOP编程 处理方法的返回类型要保持一致&#xff0c;参数和顺序保持一致&#xff0c; 可以在参数列表最后加 com.alibaba.csp.sentinel.slots.block.BlockException; …

什么是时间序列分析

时间序列分析是现代计量经济学的重要内容&#xff0c;广泛应用于经济、商业、社会问题研究中&#xff0c;在指标预测中具有重要地位&#xff0c;是研究统计指标动态特征和周期特征及相关关系的重要方法。 一、基本概念 经济社会现象随着时间的推移留下运行轨迹&#xff0c;按…

现代农业AI智能化升级之路:机器学习在现代农业领域的现状与未来发展

&#x1f9d1; 作者简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟&#xff0c;欢迎关注。提供嵌入式方向…

学习笔记-数据结构-线性表(2024-04-18)- 单向链表选择排序

试以单向链表为存储结构实现简单选择排序的算法。 实现递增排序&#xff0c;首先选择一个元素作为第一个比较值&#xff0c;遍历其他所有的元素&#xff0c;如果发现其他元素中有比它小的元素&#xff0c;则交换两个元素&#xff0c;这样每一趟都能找到符合要求的最小值 正经…

展开说说:Android Fragment完全解析-卷一

1、是什么 Fragment 中文意思是碎片&#xff0c;Android 3.0推出的一个系统组件&#xff0c;主打一个在应用界面中可模块化又可重复使用。 Fragment 它很独立&#xff0c;它可以定义和管理自己的布局&#xff0c;具有自己的生命周期&#xff0c;并且可以处理自己的输入事件。…

Android笔记: mkdirs失败,不生效怎么办

Manifest已经配置权限,代码中也动态获取权限,mkdirs一直返回false File.mkdirs()方法创建文件夹失败 1、动态申请读写权限 <!--SDCard写权限--> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!--SDCard读权…

4.18学习总结

多线程补充 等待唤醒机制 现在有两条线程在运行&#xff0c;其中一条线程可以创造一个特殊的数据供另一条线程使用&#xff0c;但这个数据的创建也有要求&#xff1a;在同一时间只允许有一个这样的特殊数据&#xff0c;那么我们要怎样去完成呢&#xff1f;如果用普通的多线程…

解决Error in writing header file of the driver

在源代码里面更新了一批常规的内容&#xff0c;编译的时候遇到一个error&#xff0c;一大片都是红的。XXX是项目名称。 Description Resource Path Location Type Generator: ERROR: Error in writing header file of the driver XXX Cpu Processor Expert Problem 表面意思是…

【学习】Jmeter、postman、python如何与数据库相互配合

在当今数字化时代&#xff0c;数据库已经成为我们日常生活中不可或缺的一部分。无论是购物、社交还是工作&#xff0c;数据库都在默默地为我们提供着高效、稳定的服务。而在众多的技术工具中&#xff0c;Jmeter、Postman和Python成为了操作数据库的三大主流技术。今天&#xff…

【嵌入式DIY实例】-指纹锁

DIY指纹锁 文章目录 DIY指纹锁1、硬件准备1.1 R307指纹传感器模介绍2、硬件接线原理图3、代码实现在这个项目中,我们将使用 Arduino 构建一个指纹门锁安全系统。 该系统可用于我们的家庭、办公室等提供安全保障。 我们还可以用它来打开门,只需将手指放在门锁上即可。 安全是许…