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.mzph.cn/bicheng/1021.shtml

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

相关文章

算法打卡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…

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;并且可以处理自己的输入事件。…

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 构建一个指纹门锁安全系统。 该系统可用于我们的家庭、办公室等提供安全保障。 我们还可以用它来打开门,只需将手指放在门锁上即可。 安全是许…

Linux管道共享内存

前言 进程虽然是独立运行的个体&#xff0c;但它们之间有时候需要协作才能完成一项工作&#xff0c;比如有两个进程需要同步数据&#xff0c;进程 A 把数据准备好后&#xff0c;想把数据发往进程 B&#xff0c;进程 B 必须被提前通知有数据即将到来&#xff0c;或者进程 A 想发…

项目七:学会使用python爬虫解析库(小白大成级)

前期我们学会了怎么使用python爬虫请求库和解析库的简单应用和了解&#xff0c;同时能够对爬虫有一个较为清晰的体系&#xff0c;毕竟简单的爬虫基本上都是请求数据——解析数据——存储数据的大概流程。 那么回忆一下&#xff0c;请求库我们学的是requests模块&#xff0c;解…

项目管理-项目开发计划介绍

目录 一、内容总览 二、项目开发计划概述 2.1 概述 2.2 项自开发计划的目的和作用 2.3 项目开发计划的内容 2.3.1 工作计划 2.3.2 人员组织计划 2.3.3 设备采购和资源供应计划 2.3.4 配置管理计划 2.3.5 进度安排计划 2.3.6 成本投资计划 2.3.7 质量保证计划 2.3.8…

实现I.MX6ULL开发板与Windows和Ubuntu系统之间的通信

虚拟机与主机之间的连接方式确实包括桥接模式、NAT模式和仅主机模式。 桥接模式&#xff08;Bridged&#xff09;&#xff1a;在桥接模式下&#xff0c;虚拟机通过虚拟交换机直接连接到主机的物理网络上&#xff0c;就像一台独立的物理机器一样&#xff0c;拥有自己的IP地址&a…

[阅读笔记23][JAM]JOINTLY TRAINING LARGE AUTOREGRESSIVE MULTIMODAL MODELS

这篇论文是24年1月发表的&#xff0c;然后是基于的RA-CM3和CM3Leon这两篇论文。它所提出的JAM结构系统地融合了现有的文本模型和图像生成模型。 主要有两点贡献&#xff0c;第一点是提出了融合两个模型的方法&#xff0c;第二点是为混合模型精心设计的指令微调策略。 下图是一个…