前言

上次我们提到了乐观锁和悲观锁,那我们知道锁的类型还有很多种,我们今天简单聊一下,公平锁和非公平锁两口子,以及他们在我们代码中的实践。

正文

开始聊之前,我先大概说一下他们两者的定义,帮大家回顾或者认识一下。

公平锁:多个线程按照申请锁的顺序去获得锁,线程会直接进入队列去排队,永远都是队列的第一位才能得到锁。

  • 优点:所有的线程都能得到资源,不会饿死在队列中。
  • 缺点:吞吐量会下降很多,队列里面除了第一个线程,其他的线程都会阻塞,cpu唤醒阻塞线程的开销会很大。

非公平锁:多个线程去获取锁的时候,会直接去尝试获取,获取不到,再去进入等待队列,如果能获取到,就直接获取到锁。

  • 优点:可以减少CPU唤醒线程的开销,整体的吞吐效率会高点,CPU也不必取唤醒所有线程,会减少唤起线程的数量。
  • 缺点:你们可能也发现了,这样可能导致队列中间的线程一直获取不到锁或者长时间获取不到锁,导致饿死。

我举个例子给他家通俗易懂的讲一下的,想了好几天终于在前天跟三歪去肯德基买早餐排队的时候发现了怎么举例了。

现在是早餐时间,敖丙想去kfc搞个早餐,发现有很多人了,一过去没多想,就乖乖到队尾排队,这样大家都觉得很公平,先到先得,所以这是公平锁咯。

那非公平锁就是,敖丙过去买早餐,发现大家都在排队,但是敖丙这个人有点渣的,就是喜欢插队,那他就直接怼到第一位那去,后面的鸡蛋,米豆都不行,我插队也不敢说什么,只能默默忍受了。

但是偶尔,鸡蛋也会崛起,叫我滚到后面排队,我也是欺软怕硬,默默到后面排队,就插队失败了。

介绍完简单的例子,大家可能会说,渣丙,这个我也知道的啊。

我们是不是应该回归真正的实现了,其实在大家经常使用的ReentrantLock中就有相关公平锁,非公平锁的实现了。

大家还记得我在乐观锁、悲观锁章节提到的Sync类么,是ReentrantLock他本身的一个内部类,他继承了AbstractQueuedSynchronizer,我们在操作锁的大部分操作,都是Sync本身去实现的。

Sync呢又分别有两个子类:FairSync和NofairSync

他们子类的名字就可以见名知意了,公平和不公平那又是怎么在代码层面体现的呢?

公平锁:

你可以看到,他加了一个hasQueuedPredecessors的判断,那他判断里面有些什么玩意呢?

代码的大概意思也是判断当前的线程是不是位于同步队列的首位,是就是返回true,否就返回false。

我总觉得写到这里就应该差不多了,但是我坐下来,静静的思考之后发现,还是差了点什么。

上次聊过ReentrantLock了,但是AQS什么的我都只是提了一嘴,一个线程进来,他整个处理链路到底是怎样的呢?

公平锁到底公平不公平呢?让我们一起跟着丙丙走进ReentrantLock的内心世界。

上面提了这么多,我想你应该是有所了解了,那一个线程进来ReentrantLock这个渣男是怎么不公平的呢?(默认是非公平锁)

我先画个图,帮助大家了解下细节:

ReentrantLock的Sync继承了AbstractQueuedSynchronizer也就是我们常说的AQS

他也是ReentrantLock加锁释放锁的核心,大致的内容我之前一期提到了,我就不过多赘述了,他们看看一次加锁的过程吧。

A线程准备进去获取锁,首先判断了一下state状态,发现是0,所以可以CAS成功,并且修改了当前持有锁的线程为自己。

这个时候B线程也过来了,也是一上来先去判断了一下state状态,发现是1,那就CAS失败了,真晦气,只能乖乖去等待队列,等着唤醒了,先去睡一觉吧。

A持有久了,也有点腻了,准备释放掉锁,给别的仔一个机会,所以改了state状态,抹掉了持有锁线程的痕迹,准备去叫醒B。

这个时候有个带绿帽子的仔C过来了,发现state怎么是0啊,果断CAS修改为1,还修改了当前持有锁的线程为自己。

B线程被A叫醒准备去获取锁,发现state居然是1,CAS就失败了,只能失落的继续回去等待队列,路线还不忘骂A渣男,怎么骗自己,欺骗我的感情。

诺以上就是一个非公平锁的线程,这样的情况就有可能像B这样的线程长时间无法得到资源,优点就是可能有的线程减少了等待时间,提高了利用率。

现在都是默认非公平了,想要公平就得给构造器传值true。

ReentrantLock lock = new ReentrantLock(true);
复制代码

说完非公平,那我也说一下公平的过程吧:

线A现在想要获得锁,先去判断下state,发现也是0,去看了看队列,自己居然是第一位,果断修改了持有线程为自己。

线程b过来了,去判断一下state,嗯哼?居然是state=1,那cas就失败了呀,所以只能乖乖去排队了。

未命名文件 (https://tva1.sinaimg.cn/large/00831rSTly1gcxaojuen2j30oa0jxgmh.jpg)

线程A暖男来了,持有没多久就释放了,改掉了所有的状态就去唤醒线程B了,这个时候线程C进来了,但是他先判断了下state发现是0,以为有戏,然后去看了看队列,发现前面有人了,作为新时代的良好市民,果断排队去了。

线程B得到A的召唤,去判断state了,发现值为0,自己也是队列的第一位,那很香呀,可以得到了。

总结:

总结我不说话了,但是去获取锁判断的源码,箭头所指的位置,现在是不是都被我合理的解释了,当前线程,state,是否是0,是否是当前线程等等,都去思考下。

作者:敖丙
链接:https://juejin.im/post/5e7212b3f265da576e64bcd1
来源:掘金

面试官:说一下公平锁和非公平锁的区别?相关推荐

  1. 阿里面试官:说一下公平锁和非公平锁的区别?

    点赞再看,养成习惯,微信搜索[三太子敖丙]关注这个互联网苟且偷生的工具人. 本文 GitHub https://github.com/JavaFamily 已收录,有一线大厂面试完整考点.资料以及我的 ...

  2. kali锁屏后无法唤醒_面试官:说一下公平锁和非公平锁的区别?

    前言 上次我们提到了乐观锁和悲观锁,那我们知道锁的类型还有很多种,我们今天简单聊一下,公平锁和非公平锁两口子,以及他们在我们代码中的实践. 正文 开始聊之前,我先大概说一下他们两者的定义,帮大家回顾或 ...

  3. 闲聊AQS面试和源码解读---可重入锁、LockSupport、CAS;从ReentrantLock源码来看公平锁与非公平锁、AQS到底是怎么用CLH队列来排队的?

    AQS原理可谓是JUC面试中的重灾区之一,今天我们就来一起看看AQS到底是什么? 这里我先整理了一些JUC面试最常问的问题? 1.Synchronized 相关问题以及可重入锁 ReentrantLo ...

  4. Java面试之锁-公平锁和非公平锁

    Java锁之公平锁和非公平锁 概念 公平锁 是指多个线程按照申请锁的顺序来获取锁,类似于排队买饭,先来后到,先来先服务,就是公平的,也就是队列 非公平锁 是指多个线程获取锁的顺序,并不是按照申请锁的顺 ...

  5. Java面试突击:公平锁和非公平锁有什么区别?

    从公平的角度来说,Java 中的锁总共可分为两类:公平锁和非公平锁.但公平锁和非公平锁有哪些区别?孰优孰劣呢?在 Java 中的应用场景又有哪些呢?接下来我们一起来看. 正文公平锁:每个线程获取锁的顺 ...

  6. 浅谈ReentrantLock的公平锁和非公平锁的区别

    前言 最近在看java并发编程这本书,已经看了点ReentrantLock的源码,以及之前有面试官问,公平锁和非公平锁有啥区别,我就只是从源码层面说了一下区别,但在性能上也有区别,今天就来说道说道. ...

  7. 【JUC并发编程06】多线程锁 (公平锁和非公平锁,死锁,可重锁)

    文章目录 6 多线程锁 (公平锁和非公平锁,死锁,可重锁) 6.1 synchronized 锁的八种情况 6.2 对上述例子的总结 6.3 公平锁和非公平锁 6.4 可重入锁 6.5 死锁 6 多线 ...

  8. reentrantlock非公平锁不会随机挂起线程?_【原创】Java并发编程系列16 | 公平锁与非公平锁...

    本文为何适原创并发编程系列第 16 篇,文末有本系列文章汇总. 上一篇提到重入锁 ReentrantLock 支持两种锁,公平锁与非公平锁.那么这篇文章就来介绍一下公平锁与非公平锁. 为什么需要公平锁 ...

  9. java锁(公平锁和非公平锁、可重入锁(又名递归锁)、自旋锁、独占锁(写)/共享锁(读)/互斥锁、读写锁)

    前言 本文对Java的一些锁的概念和实现做个整理,涉及:公平锁和非公平锁.可重入锁(又名递归锁).自旋锁.独占锁(写)/共享锁(读)/互斥锁.读写锁 公平锁和非公平锁 概念 公平锁是指多个线程按照申请 ...

最新文章

  1. 王爽 汇编语言第三版 监测点9.2 监测点9.3 补全编程,利用jcxz指令,利用loop指令,实现在内存2000H段中查找第一个值为0的字节,
  2. linux上验证cudnn是否安装成功_非root用户安装cuda与cudnn
  3. php manager 怎么用,Windows 2008 R2下如何利用PHPManager对PHP进行配置
  4. 【收藏】Zeppelin与Linkis、Scriptis的实践对比
  5. java sdk 1.7_jdk 1.7升级到1.8后显示还是1.7
  6. 使用Github Action发布函数到阿里云serverless平台
  7. 算法 --- 翻转二叉树
  8. Codeforces Round #740 (Div. 2, based on VK Cup 2021 - Final (Engine)) A-F全题解
  9. 神奇!一行代码实现删除某集合下标20-30的元素
  10. 评论语义分析 分词 分类python_用python调用ICTCLAS50进行中文分词
  11. div垂直,水平居中
  12. golang []byte和string相互转换
  13. Simple2D-24 Sprite 渲染树
  14. 我没让机器人变身,它自己就变了 | Science Robotics
  15. 304902阿里巴巴Java开发手册1.4.0
  16. 设计模式14——行为型模式之职责链模式
  17. 吉大计算机学院周柚,周柚
  18. mrp手机qq2008下载-MRP格式的手机QQ2008软件介绍及如何正确安装MRPQQ2008挂Q版
  19. div垂直居中,图片垂直居中
  20. YouTube如何开启双语显示

热门文章

  1. 《联盟》读书笔记(三):如何协调员工与公司的目标和价值观
  2. mac os 录屏快捷键_录屏软件哪个好?赶紧收藏录屏好用方法
  3. 微信小程序自定义拍照功能
  4. primeNG组件库在Angular2上的使用
  5. Android中的常用控件之进度条(ProgressBar)
  6. 【Python】绘制三维立体图
  7. 怎么样用阿里云RDS数据库
  8. excel不显示0_Excel教程:数值为0不显示的三种解决方法
  9. untiy打包发布WebGL
  10. php strtotime 2099,PHP的strtotime()函数2039年bug问题