可重入锁(ReentrantLock和synchronized原理及区别)+锁升级

2023-11-02

目录

1.Synchronized底层原理

ReentrantLock实现的原理及使用:

Java中synchronized 和 ReentrantLock 有什么不同?

追问3:synchronized锁升级的过程说一下?

追问4:synchronize锁的作用范围


可重入锁

一、基本概念和使用

可重入锁: 也叫做递归锁,指的是同一线程 外层函数获得锁之后 ,内层递归函数仍然有获取该锁的代码,但不受影响。

        在JAVA中ReentrantLock 和synchronized 都是可重入锁;ReentrantLock 在Java也是一个基础的锁,ReentrantLock 实现Lock接口提供一系列的基础函数,开发人员可以灵活的是应用函数满足各种复杂多变应用场景;

1.Synchronized底层原理

        Synchronized进过编译,会在同步块的前后分别形成monitorenter和monitorexit这个两个字节码指令。在执行monitorenter指令时,首先要尝试获取对象锁。如果这个对象没被锁定,或者当前线程已经拥有了那个对象锁,把锁的计算器加1,相应的,在执行monitorexit指令时会将锁计算器就减1,当计算器为0时,锁就被释放了。如果获取对象锁失败,那当前线程就要阻塞,直到对象锁被另一个线程释放为止。

        如果修饰的是方法,则会在方法前标记ACC_Synchronized ,本质都是获取monitor对象。

ReentrantLock实现的原理及使用:

简单来说,ReentrantLock的实现是一种自旋锁,通过循环调用CAS操作来实现加锁。它的性能比较好也是因为避免了使线程进入内核态的阻塞状态。

由于ReentrantLock是java.util.concurrent包下提供的一套互斥锁,相比Synchronized,ReentrantLock类提供了一些高级功能,主要有以下3项:

        1.等待可中断,持有锁的线程长期不释放的时候,正在等待的线程可以选择放弃等待,这相当于Synchronized来说可以避免出现死锁的情况。通过lock.lockInterruptibly()来实现这个机制。

        2.公平锁,多个线程等待同一个锁时,必须按照申请锁的时间顺序获得锁,Synchronized锁非公平锁,ReentrantLock默认的构造函数是创建的非公平锁,可以通过参数true设为公平锁,但公平锁表现的性能不是很好。
        3.锁绑定多个条件,一个ReentrantLock对象可以同时绑定对个对象。ReenTrantLock提供了一个Condition(条件)类,用来实现分组唤醒需要唤醒的线程们,而不是像synchronized要么随机唤醒一个线程要么唤醒全部线程。

Java中synchronized 和 ReentrantLock 有什么不同?

相同点:

        它们都是加锁方式同步,而且都是阻塞式的同步,也就是说当如果一个线程获得了对象锁,进入了同步块,其他访问该同步块的线程都必须阻塞在同步块外面等待,而进行线程阻塞和唤醒的代价是比较高的.

区别:

        对于Synchronized来说,它是java语言的关键字,是原生语法层面的互斥,需要jvm实现。Synchronized可以修饰实例方法,静态方法,代码块。自动释放锁。

        而ReentrantLock它是JDK 1.5之后提供的API层面的互斥锁,需要lock()和unlock()方法配合try/finally语句块来完成。需要try catch finally语句,在try中获取锁,在finally释放锁。需要手动释放锁。

        Synchronized经过编译,会在同步块的前后分别形成monitorenter和monitorexit这个两个字节码指令。在执行monitorenter指令时,首先要尝试获取对象锁。如果这个对象没被锁定,或者当前线程已经拥有了那个对象锁,把锁的计算器加1,相应的,在执行monitorexit指令时会将锁计算器就减1,当计算器为0时,锁就被释放了。如果获取对象锁失败,那当前线程就要阻塞,直到对象锁被另一个线程释放为止。
        由于ReentrantLock是java.util.concurrent包下提供的一套互斥锁,相比Synchronized, ReentrantLock类提供了一些高级功能,主要有以下3项:

        1.    等待可中断,持有锁的线程长期不释放的时候,正在等待的线程可以选择放弃等待,这相当于Synchronized来说可以避免出现死锁的情况。
        2.    公平锁,多个线程等待同一个锁时,必须按照申请锁的时间顺序获得锁,Synchronized锁非公平锁, ReentrantLock默认的构造函数是创建的非公平锁,可以通过参数true设为公平锁,但公平锁表现的性能不是很好。
        3.    锁绑定多个条件,一个ReentrantLock对象可以同时绑定对个对象。

ReenTrantLock使用:

1.Lock接口:2、ReentrantLock私有public方法3.ReentrantLock中Condition的使用4.公平锁与非公平锁5.编程灵活度和难度。

        Java中的ReentrantLock 也是实现了Java中锁的核心接口Lock,在Lock接口定义了标准函数,但是具体实现是在实体类中[类似List和ArrayList、LinkedList关系];

2、ReentrantLock私有public方法

        ReentrantLock中除了实现Lock中定义的一些标准函数外,同时提供其他的用于管理锁的public方法

3.ReentrantLock中Condition的使用
        ReentrantLock中另一个重要的应用就是Condition,Condition是Lock上的一个条件,可以多次newCondition()获得多个条件,Condition可用于线程间通信,通过Condition能够更加精细的控制多线程的休眠与唤醒,而且在粒度和性能上都优于Object的通信方法(wait、notify 和 notifyAll);

4.公平锁与非公平锁

公平锁: 是指多个线程竞争同一资源时[等待同一个锁时],获取资源的顺序是按照申请锁的先后顺序的;公平锁保障了多线程下各线程获取锁的顺序,先到的线程优先获取锁,有点像早年买火车票一样排队早的人先买到火车票;
基本特点: 线程执行会严格按照顺序执行,等待锁的线程不会饿死,但 整体效率相对比较低;

非公平锁: 是指多个线程竞争同一资源时,获取资源的顺序是不确定的,一般是抢占式的;非公平锁相对公平锁是增加了获取资源的不确定性,但是整体效率得以提升;
基本特点: 整体效率高,线程等待时间片具有不确定性;
5.编程灵活度和难度

        Synchronized的使用比较方便简洁,并且由编译器去保证锁的加锁和释放,而ReenTrantLock需要手工声明来加锁和释放锁,为了避免忘记手工释放锁造成死锁,所以最好在finally中声明释放锁。

追问3:synchronized锁升级的过程说一下?

回答:在jdk1.6后Java对synchronize锁进行了升级过程,主要包含偏向锁、轻量级锁和重量级锁,主要是针对对象头MarkWord的变化。

(1)偏向锁

为什么要引入偏向锁?

因为大多数时候是不存在锁竞争的,常常是一个线程多次获得同一个锁,因此如果每次都要竞争锁会增大很多没有必要付出的代价,为了降低获取锁的代价,才引入的偏向锁。

偏向锁的升级

当线程1访问代码块并获取锁对象时,会在java对象头栈帧中记录偏向的锁的threadID,因为偏向锁不会主动释放锁,因此以后线程1再次获取锁的时候,需要比较当前线程的threadID和Java对象头中的threadID是否一致,如果一致(还是线程1获取锁对象),则无需使用CAS来加锁、解锁;如果不一致(其他线程,如线程2要竞争锁对象,而偏向锁不会主动释放因此还是存储的线程1的threadID),那么需要查看Java对象头中记录的线程1是否存活,如果没有存活,那么锁对象被重置为无锁状态,其它线程(线程2)可以竞争将其设置为偏向锁;如果存活,那么立刻查找该线程(线程1)的栈帧信息,如果还是需要继续持有这个锁对象,那么暂停当前线程1,撤销偏向锁,升级为轻量级锁,如果线程1 不再使用该锁对象,那么将锁对象状态设为无锁状态,重新偏向新的线程。

(2)轻量级锁

为什么要引入轻量级锁?

轻量级锁考虑的是竞争锁对象的线程不多,而且线程持有锁的时间也不长的情景。因为阻塞线程需要CPU从用户态转到内核态,代价较大,如果刚刚阻塞不久这个锁就被释放了,那这个代价就有点得不偿失了,因此这个时候就干脆不阻塞这个线程,让它自旋这等待锁释放。

轻量级锁什么时候升级为重量级锁?

线程1获取轻量级锁时会先把锁对象的对象头MarkWord复制一份到线程1的栈帧中创建的用于存储锁记录的空间(称为DisplacedMarkWord),然后使用CAS把对象头中的内容替换为线程1存储的锁记录(DisplacedMarkWord)的地址;

如果在线程1复制对象头的同时(在线程1CAS之前),线程2也准备获取锁,复制了对象头到线程2的锁记录空间中,但是在线程2CAS的时候,发现线程1已经把对象头换了,线程2的CAS失败,那么线程2就尝试使用自旋锁来等待线程1释放锁

但是如果自旋的时间太长也不行,因为自旋是要消耗CPU的,因此自旋的次数是有限制的,比如10次或者100次,如果自旋次数到了线程1还没有释放锁,或者线程1还在执行,线程2还在自旋等待,这时又有一个线程3过来竞争这个锁对象,那么这个时候轻量级锁就会膨胀为重量级锁。重量级锁把除了拥有锁的线程都阻塞,防止CPU空转。

几种锁的优缺点?

错误的加锁姿势1

synchronized (new Object())

每次调用创建的是不同的锁,相当于无锁

错误的加锁姿势2

private Integer count;
synchronized (count)

        String,Boolean在实现了都用了享元模式,即值在一定范围内,对象是同一个。所以看似是用了不同的对象,其实用的是同一个对象。会导致一个锁被多个地方使用。

正确的加锁姿势

// 普通对象锁
private final Object lock = new Object();
// 静态对象锁
private static final Object lock = new Object();

追问4:synchronize锁的作用范围

回答:

(1)synchronize作用于成员变量和非静态方法时,锁住的是对象的实例,即this对象。

(2)synchronize作用于静态方法时,锁住的是Class实例

(3)synchronize作用于一个代码块时,锁住的是所有代码块中配置的对象。

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

可重入锁(ReentrantLock和synchronized原理及区别)+锁升级 的相关文章

  • 用于解析和构建逻辑表达式的 Java 库

    我正在寻找一个 Java 开源库来解析和构建类似 SQL 的表达式 例如评估表达式的有效性 例如 a x or y and b z 另外我想要一个用于构建或扩展表达式的 API 就像是 Expression exp new Expressi
  • 将 MouseListener 添加到面板

    我正在尝试将鼠标操作添加到我的面板中 这就是程序应该做的事情 编写一个程序 允许用户通过按三下鼠标来指定一个三角形 第一次按下鼠标后 画一个小点 第二次按下鼠标后 绘制一条连接前两个点的线 第三次按下鼠标后 绘制整个三角形 第四次按下鼠标会
  • 在 Java 中使用 Batik 检查和删除 SVG 中的属性

    这个问题基本上说明了一切 如何检查 SVG 是否具有 viewBox 属性 我正在使用蜡染库 我需要这个 因为我需要 至少 通知用户有一个 viewBox 属性 我可以删除它吗 使用 org w3c dom 类 您可以按照以下方式做一些事情
  • 在 jTextfield 中禁用“粘贴”

    我有一个用 Swing awt 编写的应用程序 我想阻止用户将值粘贴到文本字段中 有没有办法在不使用动作监听器的情况下做到这一点 您可以使用 null 参数调用 setTransferHandler 如下所示 textComponent s
  • 对象数组的数组(二维数组)JNI

    我正在努力创建自定义对象类型 ShareStruct 的二维数组 jobjectArray ret jobjectArray ins jobjectArray outs jclass myClass env gt FindClass env
  • 如何作为应用程序发布到页面?

    所以 我有一个应用程序 Facebook 应用程序实体 并且我有一个页面 我想使用应用程序通过java代码 通过restfb或任何其他建议 发布到页面 看起来我错过了页面授予应用程序发布权限的阶段 不知道该怎么做 谢谢你们 乌里 您只能 作
  • 最快的高斯模糊实现

    如何以最快的速度实施高斯模糊 http en wikipedia org wiki Gaussian blur算法 我要用Java来实现它 所以GPU http en wikipedia org wiki Graphics processi
  • Java 卡布局。多张卡中的一个组件

    一个组件 例如JLabel 在多张卡中使用CardLayout 目前看来该组件仅出现在它添加到的最后一张卡上 如果有办法做到这一点 我应该吗 这是不好的做法吗 或者有其他选择吗 你是对的 它只出现在 添加到的最后一张卡 中 但这与CardL
  • 本地开发的 Azure Functions 扩展包版本问题

    我有一个带有队列触发器的 Java 11 Azure 函数 该函数在部署到 Azure 时按预期工作 并正确从定义的服务总线主题中提取消息 但是 运行相同的功能locally除非我回滚版本 否则不起作用Azure Functions 绑定扩
  • JUnit5 平台启动器 API - 如果没有至少一个测试引擎,则无法创建启动器

    我正在尝试升级我们的自动化测试套件的测试能力以接受 JUnit5 测试并遵循JUnit 平台启动器 API 说明 https junit org junit5 docs current user guide launcher api我收到错
  • 如何在 HandlerInterceptorAdapter 中添加 HttpServletRequest 标头?

    我正在尝试将授权标头添加到我的请求中 作为我们切换环境时的临时解决方法 我试图在扩展 HandlerInterceptorAdapter 的拦截器中处理它 我使用 MutableHttpServletRequest 类制作here http
  • 无法从资源加载图片

    So I am trying to load a image file from a resource so that when I export my application into a jar file it could be use
  • 如何将 Java 地图转换为在 Scala 中使用?

    我正在开发一个 Scala 程序 该程序调用 Java 库中的函数 处理结果并生成 CSV 有问题的 Java 函数如下所示 Map
  • Struts 1 到 Spring 迁移 - 策略

    我有一个legacy银行应用程序编码为Struts 1 JSP现在的要求是迁移后端 目前为 MVC to Springboot MVC 后续UI JSP 将迁移到angular Caveats 1 后端不是无状态的 2 会话对象中存储了大量
  • 在 java 中运行外部应用程序但不要等待它完成

    我正在用java编写一个应用程序 允许我运行其他应用程序 为此 我使用了 Process 类对象 但当我这样做时 应用程序会等待进程结束 然后再退出 有没有办法在 Java 中运行外部应用程序 但不等待它完成 public static v
  • 为什么无法从 WEB-INF 文件夹内加载 POSModel 文件?

    我在我的 Web 项目中使用 Spring MVC 我将模型文件放在 WEB INF 目录中 String taggerModelPath WEB INF lib en pos maxent bin String chunkerModelP
  • Java 中 JButton 的击键/热键

    最初我使用 JMenu 并建立热键以使用加速器工作 它运行得很好 现在我想在 JButton 中实现相同的行为 但我陷入困境 这是我编写的代码 请分享您的想法 以便我可以走上正确的道路 import javax swing import j
  • java.lang.IllegalStateException - 提交响应后无法创建会话

    我在我的项目中使用 JSF PrimeFaces 我为此准备了一个Maven项目 当我编译项目并加载主页后 我收到以下异常 java lang IllegalStateException Cannot create a session af
  • 如何使用自定义 JDK 构建 Jenkins 项目?

    我有一个常规的 Jenkins 实例 运行一些多分支管道 该实例在 JDK 11 上运行 因为 Jenkins 并不真正支持更高版本 没关系 但不好的是 我的所有管道似乎也都受到 Java 11 的限制 Jenkins 仅使用它自己也使用的
  • 为什么java.lang.Cloneable不重写java.lang.Object中的clone()方法?

    Java 规范java lang Cloneable接口将自身定义为表示扩展它的任何对象也实现了clone 休眠的方法java lang Object 具体来说 它说 一个类实现了Cloneable接口来指示java lang Object

随机推荐

  • 09-多窗口切换-window_handles

    1 常用方法 使用背景 有些网站点击链接会新打开一个tab 如下图打开了两个浏览器窗口 元素定位正确 调试时一直报错 原因是未切换到对应的窗口句柄 切换到对应的窗口句柄才可以正常操作 current window handle 获得当前窗口
  • 联想拯救者Y7000P2023 Ubuntu20.04网卡驱动AX211安装

    sudo apt install flex bison git clone https github com intel backport iwlwifi git cd backport iwlwifi cd iwlwifi stack d
  • 2021年字节跳动74道高级程序员面试,附大厂真题面经

    安卓开发大军浩浩荡荡 经过近十年的发展 Android技术优化日异月新 如今Android 11 0 已经发布 Android系统性能也已经非常流畅 可以在体验上完全媲美iOS 但是 到了各大厂商手里 改源码 自定义系统 使得Android
  • 树的序列化与反序列化java - Kaiqisan

    大家好 都吃晚饭了吗 我是Kaiqisan 是一个已经走出社恐的一般生徒 为什么引入这个概念 在计算机中 如果我们如果想要可视化一棵树 那会是非常困难的工作 所以 我们就想到了一种最简单的方法来表示一棵树 而且只使用字符串 也可以区分每一颗
  • 如何使用DedeCMS制作网站首页轮播图?

    使用 DedeCMS 制作网站很多年了 做过不少网站 也为不少 DedeCMS 网站解决过不少小问题 轮播图 或者叫幻灯片 是每个网站 首页 都有的元素了 DedeCMS 并没有像有些网站管理程序一样 提供一个直接管理网站轮播图的功能 好几
  • 使用wget命令下载父目录下的整个子目录

    使用wget命令下载父目录下的整个子目录 命令如下 wget r level 0 E ignore length x k p erobots off np N http www remote com remote presentation
  • sqli-labs/Less-62

    欢迎界面提示我们一共由130次机会 而且还是以id作为注入点 每次重置都会随机分配表名 字段名 表格数据 首先判断注入类型 输入id 1 and 1 2 回显如下 说明不属于数字型 接着输入1 回显如下 没有回显 说明注入点带有单引号 佐证
  • 【研发必备】45 个 Git 经典操作场景,专治不会合代码

    git对于大家应该都不太陌生 熟练使用git已经成为程序员的一项基本技能 尽管在工作中有诸如 Sourcetree这样牛X的客户端工具 使得合并代码变的很方便 但找工作面试和一些需彰显个人实力的场景 仍然需要我们掌握足够多的git命令 下边
  • 6打印文件

    原题链接 满分 华为OD机试真题2023 JAVA 打印文件 若博豆的博客 CSDN博客 本来以为需要用map 还复习了一下语法 原来不需要 用vector存三元数组 两个pair嵌套就可以 include
  • 李建忠老师-设计模式

    前言 1 课程目标 理解松耦合设计思想 掌握面向对象设计原则 掌握重构技法改善设计 掌握GOF核心设计 补充 GOF Gong of Gour 就是四人帮的全称 下面这本书的作者 Design Patterns Elements of Re
  • 解决webstom failed to change read-only files

    我百思不得其解的是 为何我的文件不让我更改 变成了只读模式 后来我仔细回忆了一下 原来是因为我使用了root权限 来安装thinkjs之后 webstom没有root权限 所以我使用root 在终端敲下如下命令 即可解决问题 chown R
  • 2021-07-02

    TOC第一章概述 本章最重要的内容 1 互联网的边缘部分和核心部分的作用 其中包含分组交换的概念 答案 边缘部分由所有连接在互联网上的主机组成 这部分是用户直接使用的 用来进行通信 传送数据 音频或视频 和资源共享 核心部分有大量的网络和连
  • Windows连接虚拟机Centos7的ssh被拒绝

    1 ssh connect to host centos py port 22 Connection refused 2 启动ssh服务报错 service sshd start Job for ssh service failed bec
  • 浅蓝不惑:在线或用API生成二维码——为什么不让你的二维码有更多选择和样式?

    引言 山中何事 松花酿酒 春水煎茶 勿埋我心 什么是二维码 二维码也称为二维条码 是指在一维条码的基础上扩展出另一维具有可读性的条码 使用黑白矩形图案表示二进制数据 被设备扫描后可获取其中所包含的信息 一维条码的宽度记载着数据 而其长度没有
  • Spring Cloud 学习笔记三:搭建微服务工程之Ribbon 自定义负载均衡策略

    目录 Ribbon 自定义负载均衡策略 Ribbon 自定义负载均衡策略 通过实现 IRule 接口可以自定义负载策略 主要的选择服务逻辑在 choose 方法中 下面自定义负载策略 直接返回服务列表中第一个服务 代码如下所示 public
  • aptos中文版白皮书-前Facebook团队打造明星公链,三个优势:Move语言、Move虚拟机、合约可升级

    摘要 区块链作为一种新的互联网基础设施的崛起 导致开发者以快速增长的速度部署了数万个去中心化的应用程序 不幸的是 由于频繁的中断 高成本 低吞吐量限制和许多安全问题 区块链的使用还不普遍 为了在web3时代实现大规模采用 区块链基础设施需要
  • 春秋云境:CVE-2022-29464(WSO2文件上传漏洞)

    目录 一 题目 二 burp改包 一 题目 进入题目 是一个登录页面 这题确实没什么思路 所以看了官方POC 因为这个漏洞已经被国家cnnvd收入了 二 burp改包 burp抓包 不需要登录 刷新即可 发送到重放器 根据官方POC更改即可
  • Linux虚拟机安装Ubuntu

    一 在电脑上安装VMware workstation和Ubuntu映像文件 二 安装虚拟机 1 双击VMware workstation的exe文件 即第一张图 用管理员身份运行 一直下一步 到 更改目标文件夹 在文件夹名称处选择软件的文件
  • mysql 里面的isnull()和ifnull() is null 和 is not null

    usergrade表 2 找到里面username是null的行 SELECT FROM usergrade WHERE ISNULL USERNAME SELECT FROM usergrade WHERE USERNAME IS NUL
  • 可重入锁(ReentrantLock和synchronized原理及区别)+锁升级

    目录 1 Synchronized底层原理 ReentrantLock实现的原理及使用 Java中synchronized 和 ReentrantLock 有什么不同 追问3 synchronized锁升级的过程说一下 追问4 synchr