【前言】

ReentrantLock 是在JavaSE5之后,并发包中新增了Lock接口用来实现锁功能,它提供了与synchronized关键字类似的同步功能。同时ReentrantLock也是重入锁,就是支持重进入的锁,它表示该锁能够支持一个线程对资源的重复加锁,该锁还支持获取锁时的公平和非公平性选择。

【公平锁】

    static final class FairSync extends Sync {private static final long serialVersionUID = -3000897897090466540L;final void lock() {acquire(1);}

从代码中可以看出FairSync继承了Sync实现了同步器,也就是我们所说的AQS,如果我们调用lock方法,也就是我们调用了acquire的方法并且传入的参数为1

    public final void acquire(int arg) {if (!tryAcquire(arg) &&acquireQueued(addWaiter(Node.EXCLUSIVE), arg))selfInterrupt();}

首先我们进入tryAcquire方法

        protected final boolean tryAcquire(int acquires) {// 获取当前的线程final Thread current = Thread.currentThread();//获取状态int c = getState();//判断状态是否为0 状态为0表示没有加锁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;}}

进入这个线程我们首先获取当前线程,然后判断状态是否为加锁状态,如果是没有进行加锁的状态,则进入到hasQueuedPredecessors方法判断队列是否有值,如果没有值,则进行加锁,如果队列中有值,tryAcquire则返回false

  if (!tryAcquire(arg) &&acquireQueued(addWaiter(Node.EXCLUSIVE), arg))

!tryAcquire为true ,并且进入到了addWaiter方法中

// 将该线程new到一个节点里面Node node = new Node(Thread.currentThread(), mode);// Try the fast path of enq; backup to full enq on failure//将tail赋值给predNode pred = tail;//如果tail 不为nullif (pred != null) {//那么就将新new出来结点的前指针指向prednode.prev = pred;//将新new的节点设置为尾节点if (compareAndSetTail(pred, node)) {pred.next = node;return node;}}enq(node);return node;
    private Node enq(final Node node) {for (;;) {Node t = tail;//如果尾结点为空节点if (t == null) { // Must initialize//直接new一个新的节点if (compareAndSetHead(new Node()))tail = head;} else {node.prev = t;if (compareAndSetTail(t, node)) {t.next = node;return t;}}}}

进入到这个方法中是进入入队的操作

    final boolean acquireQueued(final Node node, int arg) {boolean failed = true;try {boolean interrupted = false;for (;;) {final Node p = node.predecessor();//判断前一个节点是否为头结点if (p == head && tryAcquire(arg)) {setHead(node);p.next = null; // help GCfailed = false;return interrupted;}if (shouldParkAfterFailedAcquire(p, node) &&parkAndCheckInterrupt())interrupted = true;}} finally {if (failed)cancelAcquire(node);}}

首先我们判断前一个节点是否为头结点,如果为头结点我们进入到了tryAcquire方法中继续进行获取锁,如果获取锁成功了,
那么设置结点为头结点。
如果该结点的上一个结点不是头结点,那么执行下面的代码

     if (shouldParkAfterFailedAcquire(p, node) &&parkAndCheckInterrupt())

shouldParkAfterFailedAcquire 方法主要逻辑是使用compareAndSetWaitStatus(pred,ws,node.SIGNAL)使用CAS将节点状态由 INITIAL 设置成 SIGNAL,表示当前线程阻塞。当 compareAndSetWaitStatus 设置失败则说明 shouldParkAfterFailedAcquire 方法返回 false,然后会在 acquireQueued 方法中死循环中会继续重试,直至compareAndSetWaitStatus 设置节点状态位为 SIGNAL 时 shouldParkAfterFailedAcquire 返回 true 时才会执行方法 parkAndCheckInterrupt 方法。

parkAndCheckInterrupt 该方法的关键是会调用 LookSupport.park 方法(关于LookSupport会在以后的文章进行讨论),该方法是用来阻塞当前线程。

如果获取锁失败的话,先将节点状态设置成SIGNAL,然后调用LookSupport.park方法使得当前线程阻塞。

【非公平锁】

      final void lock() {if (compareAndSetState(0, 1))setExclusiveOwnerThread(Thread.currentThread());elseacquire(1);}

非公平锁上来就进行获取锁

如果获取锁失败了,接下来走acquire方法

   public final void acquire(int arg) {if (!tryAcquire(arg) &&acquireQueued(addWaiter(Node.EXCLUSIVE), arg))selfInterrupt();}
        final boolean nonfairTryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();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;}

如果状态为0,则直接进行获取锁,其他的逻辑判断一样。

【公平锁和非公平锁的对比】

非公平锁会进行两次的强锁
非公平锁的效率要高
ReentrantLock默认为非公平锁

【并发】ReentrantLock中公平锁和非公平锁的理解相关推荐

  1. java中ReentrantLock实现,公平锁和非公平锁,AQS并发队列,

    一般在java中,遇到并发的时候,我们很多时候可能会使用synchronized关键字来实现锁,但是synchronized关键字有一定的缺陷(比如无法实现类似读锁.非公平),而Lock可以实现.在j ...

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

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

  3. ReentrantLock中公平锁和非公平锁的区别

    目录 背景知识 ReentrantLock的组成 概述 公平锁示意图 非公平锁示意图 源码解读 非公平锁 公平锁 代码对比 问题 知识扩展 tryLock方法 参考资料 背景知识 ReentrantL ...

  4. java投票锁_Java并发编程锁之独占公平锁与非公平锁比较

    Java并发编程锁之独占公平锁与非公平锁比较 公平锁和非公平锁理解: 在上一篇文章中,我们知道了非公平锁.其实Java中还存在着公平锁呢.公平二字怎么理解呢?和我们现实理解是一样的.大家去排队本着先来 ...

  5. java 共享锁 独占锁_Java并发编程锁之独占公平锁与非公平锁比较

    Java并发编程锁之独占公平锁与非公平锁比较 公平锁和非公平锁理解: 在上一篇文章中,我们知道了非公平锁.其实Java中还存在着公平锁呢.公平二字怎么理解呢?和我们现实理解是一样的.大家取排队本着先来 ...

  6. ReentrantLock与公平锁、非公平锁实现

    前言  最近开始读JDK源码,所有心得准备总结成一个专栏,JDK Analysis系列的第一篇,就从万众瞩目的ReentrantLock开始吧,而谈到ReentrantLock,就不得不说AQS,它是 ...

  7. java 共享锁 独占锁_java中的公平锁、非公平锁、可重入锁、递归锁、自旋锁、独占锁和共享锁...

    一.公平锁与非公平锁 1.1 概述 公平锁:是指多个线程按照申请锁的顺序来获取锁. 非公平锁:是指在多线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获取到锁,在高并发的情 ...

  8. 【高并发】怎么演示公平锁和非公平锁?

    1.概述 转:添加链接描述 本文主要用juc中的ReentrantLock来说一下公平锁和非公平锁的东西. 2. 先理解一下什么是公平锁.非公平锁? 公平锁和非公平锁体现在别人释放锁的一瞬间,如果前面 ...

  9. java中的锁(悲观锁、乐观锁、可重入锁、不可重入锁、公平锁、非公平锁、自旋锁、阻塞锁...)

    Lock接口 1.简介.地位.作用 ① 锁是一种工具,用于控制对共享资源的访问 ② Lock和synchronized,这两个是最常见的锁,它们都可以达到线程安全的目的,但是在使用和功能上又有较大的不 ...

最新文章

  1. 新上任项目经理遇到的难题
  2. 基于SSVEP-EOG的混合BCI用于机械臂控制
  3. .. 相对目录php,php 计算两个目录的相对路径
  4. python区域找图命令_python读取图片任意范围区域
  5. 软件开发管理(产品经理客户和程序员互撕解决方案)
  6. jquery-索引2019
  7. java 课后习题 编写判断从键盘输入的字符串是否为回文
  8. hadoop程序MapReduce之DataSort
  9. 浮动元素具有行内块元素特点(HTML、CSS)
  10. 2016 - 1 -17 GCD学习总结
  11. linux用tar打包文件,linux tar打包、解包命令
  12. Tenda腾达 W311U无线网卡驱动1.0版For WinXP/Vista/Win7下载-腾达无线网卡驱动-ZOL中关村在线...
  13. c语言运算符优先级(c语言运算符优先级由高到低的顺序)
  14. 【转】工业物联网技术(IIoT)的技术与挑战(PPT全文)
  15. Eyoucms易优小程序插件2.0版本上线
  16. 讲讲亿级PV的负载均衡架构!
  17. 【今日头条】米兜Java全部资料被曝光
  18. 无人超市信息管理系统——需求分析
  19. 悉尼大学商业数据科学与计算机学院,留学攻略—澳洲悉尼大学数据科学专业
  20. sql根据出生日期计算当前年龄 函数TIMESTAMPDIFF()

热门文章

  1. 电瓶车充电器充满了没有拔掉,有什么影响呢?
  2. 传智播客全新改版官网上线
  3. 如何识别哭泣csdn_网络表情NLP(一)︱颜文字表情实体识别、属性检测、新颜发现
  4. ssm毕设项目绘本馆管理系统n5wn5(java+VUE+Mybatis+Maven+Mysql+sprnig)
  5. linux中查看cpu和内存的命令,Linux系统如何查看cpu和内存信息
  6. 计算机网络工程师知识点总结
  7. Mysql之int(n)长度浅析
  8. SUMO ubuntu 源码安装
  9. c语言文件数据读取输出
  10. 烫烫烫”和“屯屯屯”