Java多线程---锁的种类都在这

2023-11-06

java锁分类   ---原文

1、悲观锁 / 乐观锁

悲观锁 :
每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,Java中synchronized和ReentrantLock等独占锁就是悲观锁思想的实现。

乐观锁:
Lock用的是乐观锁方式,每次去拿数据的时候都认为别人不会修改不上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,使用版本号机制和CAS算法实现。

两种锁的使用场景
乐观锁适用于多读场景,省去了锁的开销,加大了系统的整个吞吐量。但如果是多写的情况,一般会经常产生冲突,这就会导致上层应用会不断的进行retry,这样反倒是降低了性能,所以一般多写的场景下用悲观锁就比较合适。在Java中java.util.concurrent.atomic包下面的原子变量类就是使用了乐观锁的一种实现方式CAS实现的。


乐观锁常见的两种实现方式
1. 版本号机制
在数据表中加上一个数据版本号version字段,表示数据被修改的次数,当数据被修改时,version值会加一。当线程A要更新数据值时,在读取数据的同时也会读取version值,在提交更新时,若当前最后更新的version与操作员第一次的版本号是否相等时才更新,否则重试更新操作,直到更新成功。

2. CAS算法
即compare and swap,是一种有名的无锁算法。就是在没有线程被阻塞的情况下实现变量的同步,所以也叫非阻塞同步。
1、需要读写的内存值 V
2、进行比较的值 A
3、拟写入的新值 B
当且仅当 V 的值等于 A时,CAS通过原子方式用新值B来更新V的值,否则不会执行任何操作。一般情况下是一个自旋操作,即不断的重试。

ReentrantLock的高级操作

ReentrantLock 拥有Synchronized相同的并发性和内存语义,此外还多了定时锁等候和中断锁等候。
线程A和B都要获取对象O的锁定,假设A获取了对象O锁,B将等待A释放对O的锁定
1、如果使用 synchronized ,如果A不释放,B将一直等下去,不能被中断
2、如果 使用ReentrantLock,如果A不释放,可以使B在等待了足够长的时间以后,中断等待,而干别的事情

synchronized和lock用途区别
在非常复杂的同步应用中,请考虑使用ReentrantLock,特别是遇到下面2种需求的时候。

1.某个线程在等待一个锁的控制权的这段时间需要中断
2.需要分开处理一些wait-notify,ReentrantLock里面的Condition应用,能够控制notify哪个线程
3.具有公平锁功能,每个到来的线程都将排队等候

ReentrantLock获取锁定有三种方式

1、lock(), 如果获取了锁立即返回,如果别的线程持有锁,当前线程则一直处于休眠状态,直到获取锁
2、tryLock(), 如果获取了锁立即返回true,如果别的线程正持有锁,立即返回false
3、tryLock(long timeout,TimeUnit unit), 如果获取了锁定立即返回true,如果别的线程正持有锁,会等待参数给定的时间,在等待的过程中,如果获取了锁定,就返回true,如果等待超时,返回false;
4、lockInterruptibly:如果获取了锁定立即返回,如果没有获取锁定,当前线程处于休眠状态,直到获取锁定,或者当前线程被别的线程中断

synchronized和lock的区别


1、lock等待锁过程中可以用interrupt来中断等待,而synchronized只能等待锁的释放,不能响应中断


2、阻塞和自旋锁

自旋是指当一个线程在获取锁的时候,如果锁已经被其他线程获取,那么该线程将循环等待,然后不断判断是否能够被成功获取,自旋直到获取到锁才会退出循环。自旋是通过CAS算法进行的。

3、无锁、偏向锁、轻量级锁、重量级锁

随着竞争不断的加剧,锁要不断的升级。

(1)无锁:适用于单线程
(2)偏向锁:适用于只有一个线程访问同步块的情况,因为多个线程同时访问同步块,给某一个线程特权是不合理的
(3)轻量级锁:竞争不是太多,循环等待消耗CPU资源的线程的数量在可接受的范围
(4)重量级锁:多个线程同时竞争资源,只让一个线程运行,其余的线程都阻塞
 

*注意为了避免无用的自旋,轻量级锁一旦膨胀为重量级锁就不会再降级为轻量级锁了;偏向锁升级为轻量级锁也不能再降级为偏向锁。一句话就是锁可以升级不可以降级,但是偏向锁状态可以被重置为无锁状态。

这几种锁的优缺点(偏向锁、轻量级锁、重量级锁)

 

4、公平锁和非公平锁
公平锁是指多个线程按照申请锁的顺序来获取锁。非公平锁是指多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获取锁。有可能,会造成优先级反转或者饥饿现象。
对于Synchronized和ReentrantLock而言,是一种非公平锁。但是ReentrantLock通过构造函数指定该锁是公平锁,通过AQS的来实现线程调度,AQS由三个部分组成
State:当前线程锁的个数
exclusiveOwerThread:当前占有锁的线程 
CLH队列等待运行的线程。

1 、线程1 CAS算法A=V(state)=0,修改state的值为1
2、 线程1又想获取锁,此时A=V(state)=1,state再加1,无论A想获得多少次,只是state+1
3 、线程2 进行CAS比较,发现A不等于V,并且发现state不等于0,直接到CLH列队中等待。线程3和线程4也一样到CLH队列中等待。如果先来的线程先排队,获取锁的优先权,则为公平锁。如果,无视等待队列,直接尝试获取锁,则为非公平锁。

队列如果已经满了,该怎么办呢?
无法进入队列的线程,进入ArrayBlockingQueue,等队列有空位再进入队列


5、可重入锁和不可重入锁
可重入锁又名递归锁,是指在同一个线程在外层方法获取锁的时候,在进入内层方法会自动获取锁。说的有点抽象,下面会有一个代码的示例。对于Java ReentrantLock而言, 他的名字就可以看出是一个可重入锁,其名字是Reentrant Lock重新进入锁。对于Synchronized而言,也是一个可重入锁。可重入锁的一个好处是可一定程度避免死锁。

public sychrnozied void test() {
    xxxxxx;
    test2();
}

public sychronized void test2() {
    yyyyy;
}

在上面代码段中,执行 test 方法需要获得当前对象作为监视器的对象锁,但方法中又调用了 test2 的同步方法。

1、如果锁是具有可重入性的话,那么该线程在调用 test2 时不需要再次获得当前对象的锁,可以直接进入 test2 方法进行操作。

2、如果锁是不具有可重入性的话,那么该线程在调用 test2 前会等待当前对象锁的释放,实际上该对象锁已被当前线程所持有,不可能再次获得。

如果锁是不具有可重入性特点的话,那么线程在调用同步方法、含有锁的方法时就会产生死锁。


6、互斥锁和共享锁

互斥锁是指该锁一次只能被一个线程所持有。共享锁是指该锁可被多个线程所持有。
对于Java ReentrantLock而言,其是互斥锁。对于Synchronized而言,当然是互斥锁
但是对于Lock的另一个实现类ReentrantReadWriteLock,其读锁是共享锁,其写锁是互斥锁。读锁的共享锁可保证并发读是非常高效的,读写,写读 ,写写的过程是互斥的。互斥锁与共享锁也是通过AQS来实现的,通过实现不同的方法实现独享或者互斥

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java多线程---锁的种类都在这 的相关文章

随机推荐

  • 可动态增加、删除的全局蒙灰弹层

    import React Component from react import PropTypes from prop types import assign from object assign import from lodash i
  • 如何编写 Kubernetes 的 YAML 文件?

    声明 本文出自 CNCF 帖子最初发表于 ARMO 由研发副总裁兼联合创始人 Ben Hirschberg 撰写 已获得授权 感谢 山河已无恙 整理 西狩xs 校对 以下为翻译全文 分享给大家 尽管 Kubernetes 越来越受欢迎 但它
  • 如何使用OpenCV保存.mp4格式文件

    fourcc cv2 VideoWriter fourcc mp4v out cat cv2 VideoWriter save mp4 fourcc 24 640 360 True 保存位置 格式 out cat write image 保
  • ElementUI 之el-table-column 格式化属性(日期格式化)

    如果想对表格某一列的内容格式化 性别 日期显示 可用 formatter 属性 实战 日期显示 在method 定义formatDate 方法 formatDate row column 获取单元格数据 let data row colum
  • 数组和指针笔试题解析之【指针】

    目录 笔试题1 笔试题2 笔试题3 笔试题4 笔试题5 笔试题6 笔试题7 笔试题8 笔试题1 int main int a 5 1 2 3 4 5 int ptr int a 1 printf d d a 1 ptr 1 return 0
  • 微信小程序项目源码-50套微信小程序毕业设计的项目实战(附源码+论文+演示视频)

    大家好 我是职场程序猿 感谢您阅读本文 欢迎一键三连哦 今天给大家分享50 基于微信小程序的毕业设计 这些项目都经过精心挑选 涵盖了不同的实战主题和用例 可做毕业设计和课程设计参考 除了源码 对于大部分项目实现的功能都有相应的介绍 并且配有
  • docker基础篇-----02-----docker帮助命令、镜像命令、容器命令

    参考文章 学习笔记 尚硅谷周阳老师的Docker教程学习笔记 一 Docker常用命令 1 docker帮助命令 1 查看docker版本 docker version 2 查看docker信息 docker info 3 docker帮助
  • DeFi进化之路

    DeFi经过两年多的蛰伏 在2020年夏天爆发 本文谨代表作者个人观点 不代表火星财经立场 该内容旨在传递更多市场信息 不构成任何投资建议 来源 蓝狐笔记 DeFi经过两年多的蛰伏 在2020年夏天爆发 从6月中旬到现在 仅仅过了三个月的时
  • 【Chatgpt 公众号问答】使用python编写 带上下文 多端部署实现

    效果展示 功能列 多端部署 有多种部署方式可选择且功能完备 目前已支持个人微信 微信公众号和企业微信应用等部署方式 基础对话 私聊及群聊的消息智能回复 支持多轮会话上下文记忆 支持 GPT 3 GPT 3 5 GPT 4模型 语音识别 可识
  • SpringBoot实现短信登陆功能

    大家好我是小羽 这段时间做项目用到了手机短信登陆的功能 在此记录一下 欢迎大家来关注我的微信公众号Java小羽 一 注册阿里云账号 登陆阿里云 直接用支付宝扫码就可以登陆注册 点击控制台 3 点击侧边栏 4 搜索短信服务 5 选择类型 6
  • window.location进行页面重定向

    host 和 hostname 的区别 host将包括端口号 而hostname只返回主机名 更改 URL 属性 开始 https segmentfault com window location pathname tidbits 设置 p
  • electerm可用的 类termius风格主题

    目录 介绍 UI主题配置 终端背景图片 注意 最终效果 介绍 electerm可用的termius风格主题及背景图片 资源来自https github com Hope IT Works electerm theme termius UI主
  • 大屏项目的优化性能(很全)--Vue+echarts+轮播定时出现的白屏,卡死,

    1 问题表现 项目是轮播一个页面多个组件的形式来展示页面中的图表 模板 一个组件模板当中有3 4个图表 定时轮播接口 但是页面经常白屏 且占用工控机的CPU资源消耗太大 固来优化性能 2 项目自测 chrome的调试工具测试发现CPU占用特
  • Sybase 存储过程中IF的用法

    Sybase 存储过程中IF的用法 i val 为参数 if i val 0 or i val is null then begin 执行内容 end end if 转载于 https www cnblogs com lizm166 p 9
  • Opencv计算机视觉图像识别实战(28249人在学,102小节,时长:14小时)

    文章末尾有联系方式 Opencv计算机视觉实战课程旨在帮助大家快速掌握机器视觉领域必备知识点原理及其在Opencv中的使用方法 课程风格通俗易懂 用最接地气的方式来讲解晦涩难懂的知识点 整体设计以项目实战来驱动学习 课程中所有代码均使用Py
  • MySQL夺命16问,你能坚持到第几问?

    前言 MySQL在面试中经常被问到 本文总结了面试中的经典问题 1 数据库三大范式是什么 第一范式 每个列都不可以再拆分 第二范式 在第一范式的基础上 非主键列完全依赖于主键 而不能是依赖于主键的一部分 第三范式 在第二范式的基础上 非主键
  • ftp服务器保存文件路径怎么写,ftp 服务器 文件路径怎么写

    ftp 服务器 文件路径怎么写 内容精选 换一换 您需要参见 开发环境安装指南 安装开发环境 获取以下文件 从ACLlib组件的安装目录 acllib include acl目录下获取调用AscendCL接口所需的头文件 从ACLlib组件
  • 文件路径中文编码问题解决方案之一

    设置代码页为简体中文 936是简体中文的代码页 std locale loc1 std locale global std locale 936 在这里使用 fstream ifstream ofstream fstream binary
  • huggingface模型--手动下载并保存

    timeout 下载模型超时 一般是最大的那个模型下载超时 其他依赖文件下载都没问题 ConnectionError HTTPSConnectionPool host cdn lfs huggingface co port 443 Read
  • Java多线程---锁的种类都在这

    java锁分类 原文 1 悲观锁 乐观锁悲观锁 每次去拿数据的时候都认为别人会修改 所以每次在拿数据的时候都会上锁 Java中synchronized和ReentrantLock等独占锁就是悲观锁思想的实现 乐观锁 Lock用的是乐观锁方式