面试官:你说说ReentrantLock和Synchronized区别

大家好!又和大家见面了。为了避免面试尴尬,今天同比较通俗语言和大家聊下ReentrantLock和Synchronized区别!

使用方式


Synchronized可以修饰实例方法,静态方法,代码块。自动释放锁。 ReentrantLock一般需要try catch finally语句,在try中获取锁,在finally释放锁。需要手动释放锁。

实现方式


Synchronized是重量级锁。重量级锁需要将线程从内核态和用户态来回切换 。如:A线程切换到B线程,A线程需要保存当前现场,B线程切换也需要保存现场。这样做的缺点是耗费系统资源。 ReentrantLock是轻量级锁。采用cas+volatile管理线程 ,不需要线程切换切换,获取锁线程觉得自己肯定能成功,这是一种乐观的思想(可能失败)。

用一个形象例子来说明:比如您在看这篇文章时,觉得"重量级锁"概念不是很明白,就立刻去翻看关于"重量级锁"的其他文章,过会儿回头再继续往下面看, 这种行为们称为切换。保存现场的意思就是你大脑需要记住你跳跃的点然后继续阅读,如果文章篇幅大,你的大脑可能需要记忆越多的东西,会越耗费脑神经。同理,在轻量级锁中,你觉得"重量级锁"概念不是很明白,他不会立刻去翻看其他文章,他会坚持会儿继续看,如果实在不明白再去翻资料了。需要注意的是:这是两种不一样的思维方式,前者是被动阻塞悲观锁,状态是block,后者是主动的阻塞乐观锁,状态是wait。

公平和非公平


Synchronized只有非公平锁。 ReentrantLock提供公平和非公平两种锁,默认是非公平的。公平锁通过构造函数传递true表示。

用一个形象例子来说明:排队打饭,Synchronized允许插队,如果ReentrantLock是公平锁,就不许插队了。

可重入锁


Synchronized和ReentrantLock都是可重入的,Synchronized是本地方法是C++实现,而ReentrantLock是JUC包用Java实现。

用一个形象例子来说明:如下图:一个房中房,房里外各有一把锁,但只有唯一的钥匙可以开,拥有钥匙的人可以先进入门1,再进入门2,其中进入门2就是叫锁可重入了。

在ReentrantLock中,重入次数用整形state表示。进入1次递增1次,出来1次递减1次。

image.png

可中断的


Synchronized是不可中断的。 ReentrantLock提供可中断和不可 中断两种方式。 其中lockInterruptibly方法表示可中断,lock方法表示不可中断。

用一个形象例子来说明:叫练和叫练女朋友一起去做核酸,叫练女朋友排在前面,所以叫练女朋友进门先做,叫练在门外排队等待过程中突然接到领导电话要回去修改bug,叫练现在有两种选择,1.不和女朋友打招呼,立即回去修改bug,2.等待女朋友做完核酸,进去和女朋友打个招呼,然后回去修改bug。这两种情况最终都会导致一个结果,叫练无法完成核酸,在这两种情况中,虽然叫练都被领导中断了,但第一种情况叫练立即反馈领导叫可中断,第二种情况是叫练为了不做单身狗,打个招呼再去修改bug,需要注意的是"打招呼"需要提前获取锁,也就是需要等待叫练女朋友做完核酸检测。如果是你,遇到叫练这种情况,你会怎么办?期待你的答复!点关注,不迷路,是叫练【公众号】,边叫边练。

条件队列


Synchronized只有一个等待队列。 ReentrantLock中一把锁可以对应多个条件队列。通过newCondition表示。

用一个形象例子来说明:母鸡下蛋和捡蛋人对应生产者和消费者,母鸡产蛋后,捡蛋人需要被母鸡通知,母鸡产蛋过程中,其中捡蛋人就会入条件队列(等待队列)。捡蛋人捡蛋完成后,捡蛋人需要通知母鸡继续产蛋,捡蛋人捡蛋过程中,母鸡也需要加入条件队列等待。 注意:有几个概念需要说明下。同步队列,条件队列和等待队列。 同步队列:多线程同时竞争一把锁失败被挂起的线程。 条件队列:正在执行的线程调用await/wait,从同步队列加入的线程会进入条件队列。正在执行线程调用signal/signalAll/notify/notifyAll,会将条件队列一个线程或多个线程加入到同步队列。 等待队列:和条件队列一个概念。

总结


今天们用通俗易懂的文字描述了ReentrantLock和Synchronized关系。喜欢的请点赞加评论哦!点关注,不迷路,是叫练【公众号】,边叫边练。期待们下次再见! tempimage1611629165941.gif

[] ) [](top

原文创作:叫练

原文链接:https://www.cnblogs.com/jiaolian/p/14329299.html

文章列表

更多推荐

更多
  • Java测试驱动开发-十二、通过实现连续交付利用 TDD 案例研究可怕的赌博公司,探索代码库,释放程序,部署到生产环境,增加测试覆盖率,结论,可能的改进,实施持续集成,走向持续交付,詹金斯装置,自动化构建,第一次执行,下一步是什么?,这仅仅是开始,这不一定是结束, “没有什么比结果更能说
  • Java测试驱动开发-一、为什么我应该关心测试驱动的开发? 为什么是 TDD?,理解 TDD,红绿重构,速度是关键,这与测试无关,测试,黑盒测试,白盒试验,质量检查和质量保证之间的区别,更好的测试,嘲笑,可执行文件,无调试, 这本书是由开发人员为开发人员编写的。因此,大部分学习将通过代码进
  • Java测试驱动开发-十一、把它们放在一起 简而言之,TDD,最佳做法,命名约定,过程,开发实践,工具, “如果你总是做你一直做的事,那么你将永远得到你一直得到的。”——阿尔伯特·爱因斯坦我们经历了大量的理论和更多的实践。整个旅程就像一列高速行驶的火车,我们几乎没有
  • Java测试驱动开发-零、前言 这本书是给谁的,充分利用这本书,下载示例代码文件,下载彩色图像,使用的惯例, 测试驱动开发已经有一段时间了,很多人还没有采用它。这背后的原因是 TDD 很难掌握。尽管这个理论很容易掌握,但要真正精通它需要大量的实践。本书的作者多年
  • Java测试驱动开发-四、单元测试—关注你做了什么,而不是已经做了什么 单元测试什么是单元测试?,为什么要进行单元测试?,代码重构,为什么不专门使用单元测试呢?,用 TDD 进行单元测试,TestNG,TestNG 与 JUnit 摘要,遥控船舶要求,遥控船舶的研制,项目设置,助手类,需求–起点和方向,规格
  • Java测试驱动开发-五、设计—如果它不可测试,那么它就设计得不好 我们为什么要关心设计?,设计原则,你不会需要它的,不要重复你自己,保持简单和直接,奥卡姆剃刀,坚实的原则,连接 4,要求,测试 Connect 4 的最后一个实现,要求 1–游戏的棋盘,要求 2–介绍光盘,要求 3–球员轮换,要求 4–
  • Java测试驱动开发-二、工具、框架和环境 吉特,虚拟机,Vagrant,Docker,构建工具,综合发展环境,创意演示项目,单元测试框架,朱尼特,TestNG,Hamcrest 和 AssertJ,汉克雷斯特,资产,代码覆盖工具,杰科科,模拟框架,Mockito,轻松的,模拟的
  • Java测试驱动开发-六、模拟—删除外部依赖项 嘲笑,为什么嘲笑?,术语,模拟对象,Mockito,Tic Tac Toe v2 要求,开发 TicTacToe v2,要求 1–门店移动,规范–数据库名称,实施,规范–Mongo 集合的名称,实施,重构,规范–将项目添加到 Mongo
  • Java测试驱动开发-九、重构遗留代码—使其再次年轻 遗留代码,遗留代码示例,识别遗留代码的其他方法,遗留代码更改算法,应用遗留代码更改算法,确定变化点,寻找测试点,打破依赖关系,写作测试,卡塔演习,卡塔遗产酒店,描述,技术意见,添加新功能,黑盒或峰值测试,初步调查,如何找到重构的候选对象
  • Java测试驱动开发-八、BDD—与整个团队合作 不同规格,文档,编码员的文档,非编码人员的文档,行为驱动开发,叙述,情节,书店 BDD 故事,杰伯哈夫,JBehave 转轮,未决步骤,Selenium 和 Selenide,JBehave 步骤,最终验证, “我不是一个优秀的程
  • 近期文章

    更多
    文章目录

      推荐作者

      更多