看到文章的标题是不是很诧异,一个搞技术的为什么要搞这么文艺的话题呢?标题说关锁千重,是不是很形象,我们在开发中的锁不也是多种多样么?

Lock

既然之前说了锁千重,那锁到底有多少种,他们的分类又是怎么区分的,为什么这么区分?我来给大家解释一下。

为什么加锁?

面试中有很多时候会问到,为什么加锁?加锁是起到什么作用?

而实际上在我们的开发过程中会出现并发的情况,比如说两个人几乎同时点击了某一个按钮,这个时候就可以简单的理解成并发,那么到底谁先谁后?
程序中就很可能出现错误,当资源出现共享的时候,就会开始涉及到并发了,这个时候我们就可能会用到锁了,来锁住某一个资源,等我用过之后,你才能动。
这就是为什么使用锁。

锁的分类

  1. 公平锁/非公平锁
  2. 可重入锁
  3. 独享锁/共享锁
  4. 互斥锁/读写锁
  5. 乐观锁/悲观锁
  6. 分段锁
  7. 偏向锁/轻量级锁/重量级锁
  8. 自旋锁

第一次分享,我们就先说这个公平锁和非公平锁。之后会在后序的文章中继续解析!

何为公平?何为非公平?在我们日常生活中的理解不就是对等的就是公平,不对等的就是不公平?
其实差不多的。

公平锁是指多个线程按照申请锁的顺序来获取锁

非公平锁是指多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获取锁。有可能,会造成优先级反转或者饥饿现象。

在JAVA的代码中什么是公平锁什么又是非公平的锁呢?

一种是使用Java自带的关键字synchronized对相应的类或者方法以及代码块进行加锁,

而另一种是ReentrantLock,前者只能是非公平锁,而后者是默认非公平但可实现公平的一把锁。

上面的类图看起来很不舒服,因为关于ReentrantLock这个锁,确实是没有很好的配图,我们可以自己画出来理解一下

我们先看非公平锁,我画图大家理解一下,就像公共厕所,不要嫌弃恶心,但是绝对容易理解

上面这幅图,加入说图中的管理员是Lock,然后现在A来了,说我要去厕所,这时候管理员一看,厕所没人,那好你进去把,然后A就进去了。

这个时候WC里面是有A的,正在进行式,这时候B来了,B也想去厕所

但是这个时候WC里面是有A的,然后管理员Lock看了一下,里面有人,排队把。。。

然后这B就得憋着,去进入队列去排队,然后又来了个C,这时候A还在里面,C只能也去排队,

就是这个样子的

这时候又过了一小会来了个D,也想去WC,这时候A恰好结束了,

这时候非公平锁就上场了,Lock管理员一看,里面没人,D你进去把,这时候就是这样的。

然后这时候因为A出来了之后说,我结束了,然后B正准备进去的时候,里面又有了D,这就是出现了非公平锁

而非公平锁的调用就是
A被Lock --> B去wait–> C在B后面wait --> A结束了,unlock -->非公平锁compareAndSetState(0, acquires),里面没人 -->D被Lock
这时候A释放锁lock.release,–>结果晚了一步,没进去,只能继续等着

这就是非公平锁的简单的一种理解,道理其实挺简单的,
而公平锁就不一样了,Lock管理员会告诉新来的D,你前面已经有好几个在排号的了,你想进去,去后边排队。

公平锁的调用是这样子的。

前面其实都是一样的,但是当D来的时候就不一样了,

D来的时候–>lock知道了–>直接调用hasQueuedPredecessors()告诉D有人在排队,你去后边排队,这样子下来就实实在在的保证了公平了。

接下来我们看看ReentrantLock的源代码实现,然后解释一下


public class ReentrantLock implements Lock, java.io.Serializable {/*同步器提供所有实现机制 */private final Sync sync;/**此锁的同步控制基础。将转换为下面的公平和非公平版本。使用AQS状态表示锁定的保持数。*/abstract static class Sync extends AbstractQueuedSynchronizer {private static final long serialVersionUID = -5179523762034025860L;/**执行{@link Lock#lock}。子类化x的主要原因是允许非公平版本的快速路径。*/abstract void lock();/*** 执行非公平的tryLock。 tryAcquire在子类中实现,但两者都需要tryf方法的非公平尝试。注意在这里执行的是非公平锁也就是说在判断方法compareAndSerState的时候,新的线程可能抢占已经排队的线程的锁的使用权*/final boolean nonfairTryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();//状态为0,说明当前没有线程占有锁if (c == 0) {if (compareAndSetState(0, acquires)) {setExclusiveOwnerThread(current);return true;}}else if (current == getExclusiveOwnerThread()) {int nextc = c + acquires;if (nextc < 0) // overflowthrow new Error("Maximum lock count exceeded");setState(nextc);return true;}return false;}protected final boolean tryRelease(int releases) {int c = getState() - releases;if (Thread.currentThread() != getExclusiveOwnerThread())throw new IllegalMonitorStateException();boolean free = false;if (c == 0) {free = true;setExclusiveOwnerThread(null);}setState(c);return free;}protected final boolean isHeldExclusively() {// While we must in general read state before owner,// we don't need to do so to check if current thread is ownerreturn getExclusiveOwnerThread() == Thread.currentThread();}final ConditionObject newCondition() {return new ConditionObject();}// Methods relayed from outer classfinal Thread getOwner() {return getState() == 0 ? null : getExclusiveOwnerThread();}final int getHoldCount() {return isHeldExclusively() ? getState() : 0;}final boolean isLocked() {return getState() != 0;}/**从流中重构实例(即反序列化它)。*/private void readObject(java.io.ObjectInputStream s)throws java.io.IOException, ClassNotFoundException {s.defaultReadObject();setState(0); // reset to unlocked state}}
}}

上面的源码都是说的是非公平锁的,我们在看看源码中对公平锁又是怎么进行定义的!

/**同步对象以进行公平锁定*/static final class FairSync extends Sync {private static final long serialVersionUID = -3000897897090466540L;final void lock() {acquire(1);}/**tryAcquire的公平版本。除非递归呼叫或没有服务员或是第一个,否则不授予访问权限。在这里有一个hasQueuedPredecessors的方法,就是这个方法来保证我们不论是新的线程还是已经在进行排队的线程都顺序的去使用锁*/protected final boolean tryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();if (c == 0) {if (!hasQueuedPredecessors() &&compareAndSetState(0, acquires)) {setExclusiveOwnerThread(current);return true;}}else if (current == getExclusiveOwnerThread()) {int nextc = c + acquires;if (nextc < 0)throw new Error("Maximum lock count exceeded");setState(nextc);return true;}return false;}}

解释完了,我们来做个总结
总结一:

  1. 公平锁:老的线程排队使用锁,新线程仍然排队使用锁。
  2. 非公平锁:老的线程排队使用锁;但是新的线程是极有可能抢占已经在排队的线程的锁。

以后我会更新关于锁的一些文章,希望大家能够指点一下,也能够共同的讨论进步,谢谢!

云阶月地,关锁千重(一.公平和非公平)相关推荐

  1. 云阶月地,关锁千重(一.独享锁/共享锁)

    之前在的文章中已经写了公平锁和非公平锁了,接下来就该介绍第二种锁了,他就是共享锁和独享锁,顾名思义,独享,只能被一个线程 所持有,而共享,就是说可以被多个线程所共有. 锁的分类 公平锁/非公平锁 可重 ...

  2. Java锁之公平和非公平锁

    Java锁之公平和非公平锁 目录 公平锁和非公平锁概念 公平锁和非公平锁区别 ReentrantLock和synchronized是公平锁还是非公平锁? 1. 公平锁和非公平锁概念 公平锁:是指多个线 ...

  3. java并发编程(三十五)——公平与非公平锁实战

    前言 在 java并发编程(十六)--锁的七大分类及特点 一文中我们对锁有各个维度的分类,其中有一个维度是公平/非公平,本文我们来探讨下公平与非公平锁. 公平|非公平 首先,我们来看下什么是公平锁和非 ...

  4. 公平锁和非公平锁-ReentrantLock是如何实现公平、非公平的

    转载:https://www.jianshu.com/p/5104cd94dbe0 1.什么是公平锁与非公平锁 公平锁:公平锁就是保障了多线程下各线程获取锁的顺序,先到的线程优先获取锁. 非公平锁:非 ...

  5. java -锁(公平、非公平锁、可重入锁【递归锁】、自旋锁)

    1.公平锁.非公平锁 2.可重入锁(递归锁) 3.自旋锁 AtomicReference atomicReference = new AtomicReference();//原子引用线程 下面代码5秒 ...

  6. java公平索非公平锁_java中的非公平锁不怕有的线程一直得不到执行吗

    首先来看公平锁和非公平锁,我们默认使用的锁是非公平锁,只有当我们显示设置为公平锁的情况下,才会使用公平锁,下面我们简单看一下公平锁的源码,如果等待队列中没有节点在等待,则占有锁,如果已经存在等待节点, ...

  7. 乐观锁、悲观锁和公平、非公平

    今天心情:我是一个程序员,现在已经走向了逼不得已通过写文章赚取流量来谋生的道路.可是现在流量惨淡,可是我并不惊慌.奥里给. 详细内容链接地址:https://zhuanlan.zhihu.com/p/ ...

  8. java公平索非公平锁_Java 并发编程中使用 ReentrantLock 替代 synchronized

    Java 5 引入的 Concurrent 并发库软件包中,提供了 ReentrantLock 可重入同步锁,用来替代 synchronized 关键字原语,并可提供更好的性能,以及更强大的功能.使用 ...

  9. 谈谈java并发锁(重入锁、读写锁、公平锁)

    目录 重入锁 简单重入锁 重入锁的等待通知(Condition) 多Condition 公平锁和非公平锁 读写锁ReentrantReadWriteLock 锁优化总结: 重入锁和读写锁,他们具有比s ...

最新文章

  1. 解决MVC返回Json中日期格式问题
  2. h5滚动时侧滑出现_H5触摸事件中如何判断用户滑动方向
  3. [原创][连载].基于SOPC的简易数码相框 - Nios II SBTE部分(软件部分) - 从SD卡内读取图片文件,然后显示在TFT-LCD上...
  4. UA MATH563 概率论的数学基础 中心极限定理16 Kolmogorov 3-series定理
  5. MUI H5+ APP 分享H5连接 通过scheme唤醒APP
  6. java第六章工具包6.1P6-01.Collections 2020.4.3+7
  7. 对现有的所能找到的DDOS代码(攻击模块)做出一次分析----CC篇
  8. C++ 高级篇(一)—— 模板(Templates)
  9. MYSQL的集群的安装与配置(mysql-5.1.21)
  10. ajax通过什么实现,ajax(通过jQuery实现)
  11. 回文串判断(string类:反转reverse)
  12. 基于JAVA+SpringMVC+Mybatis+MYSQL的音乐播放系统
  13. Springboot(java)程序部署到k8s
  14. 将coco数据集转为voc格式代码
  15. b宝塔 centos端口更改_centos修改ssh默认端口号的方法示例
  16. 2014 传播一点正能量
  17. c语言 滑窗法_滑窗算法
  18. taobao滑动验证码解决方法
  19. Error: java.lang.RuntimeException: Crunching Cruncher xxx.9.png failed,
  20. Rust reqwest框架开启cookie

热门文章

  1. C++封装dll供C#调用获取U盘/磁盘序列号信息
  2. @value 读取yml没有读到
  3. FreeMarker 模板生成 PDF电子凭证/图片
  4. python能做界面吗_如何使用pyQT做pythonGUI界面|
  5. 在nuxt中使用sass
  6. layui 多图上传和删除图片
  7. 浅识WebGL和Three.js
  8. 优麒麟20.10 wifi 开关打不开解决方案
  9. 随机模拟在多排服务器上的应用,在Excel中应用随机函数模拟多服务台单队列排队系统...
  10. 最全解决方法:未解压的word文档修改保存后找不到