ReentrantLock简介

ReentrantLock重入锁,是实现Lock接口的一个类,也是在实际编程中使用频率很高的一个锁, 支持重入性,表示能够对共享资源能够重复加锁,即当前线程获取该锁再次获取不会被阻塞。 ReentrantLock还支持公平锁和非公平锁两种方式。 那么,要想完完全全的弄懂ReentrantLock的话, 主要也就是ReentrantLock同步语义的学习:

  1. 重入性的实现原理

  1. 公平锁和非公平锁

重入性的实现原理

要想支持重入性,就要解决两个问题:

  • 1. 在线程获取锁的时候,如果已经获取锁的线程是当前线程的话则直接再次获取成功

  1. 由于锁会被获取n次,那么只有锁在被释放同样的n次之后,该锁才算是完全释放成功

针对第一个问题,我们来看看ReentrantLock是怎样实现的, 以非公平锁为例,判断当前线程能否获得锁为例,核心方法为nonfairTryAcquire(),源码如下:

final boolean nonfairTryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
    //1. 如果该锁未被任何线程占有,该锁能被当前线程获取
if (c == 0) {
        if (compareAndSetState(0, acquires)) {
            setExclusiveOwnerThread(current);
            return true;
        }
    }
//2.若被占有,检查占有线程是否是当前线程
    else if (current == getExclusiveOwnerThread()) {
// 3. 再次获取,计数加一
        int nextc = c + acquires;
        if (nextc < 0) // overflow
            throw new Error("Maximum lock count exceeded");
        setState(nextc);
        return true;
    }
    return false;
}

为了支持重入性,在第二步增加了处理逻辑,如果该锁已经被线程所占有了, 会继续检查占有线程是否为当前线程, 如果是的话,同步状态加1返回true,表示可以再次获取成功。每次重新获取都会对同步状态进行加1的操作。

针对第二个问题,依然还是以非公平锁为例,核心方法为tryRelease,源码如下:

protected final boolean tryRelease(int releases) {
//1. 同步状态减1
    int c = getState() - releases;
    if (Thread.currentThread() != getExclusiveOwnerThread())
        throw new IllegalMonitorStateException();
    boolean free = false;
    if (c == 0) {
//2. 只有当同步状态为0时,锁成功被释放,返回true
        free = true;
        setExclusiveOwnerThread(null);
    }
// 3. 锁未被完全释放,返回false
    setState(c);
    return free;
}

重入锁的释放必须得等到同步状态为0时锁才算成功释放,否则锁仍未释放。 如果锁被获取n次,释放了n-1次,该锁未完全释放返回false,只有被释放n次才算成功释放,返回true。

公平锁与非公平锁

ReentrantLock支持两种锁:

  • 公平锁

  • 非公平锁

何谓公平性,是针对获取锁而言的,如果一个锁是公平的,那么锁的获取顺序就 应该符合请求上的绝对时间顺序,满足FIFO。 ReentrantLock的无参构造方法是构造非公平锁,源码如下:

public ReentrantLock() {
    sync = new NonfairSync();
}

ReentrantLock的有参构造方法,传入一个boolean值,true时为公平锁,false时为非公平锁,源码如下:

public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}

公平锁的获取,tryAcquire()方法,源码如下:

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;
  }
}

逻辑与nonfairTryAcquire基本上一致, 唯一的不同在于增加了hasQueuedPredecessors的逻辑判断, 方法名就可知道该方法用来判断当前节点在同步队列中是否有前驱节点的判断, 如果有前驱节点说明有线程比当前线程更早的请求资源,根据公平性,当前线程请求资源失败。 如果当前节点没有前驱节点的话,才有做后面的逻辑判断的必要性。 公平锁每次都是从同步队列中的第一个节点获取到锁, 而非公平性锁则不一定,有可能刚释放锁的线程能再次获取到锁。

公平锁与非公平锁的比较:

  • 公平锁每次获取到锁为同步队列中的第一个节点,保证请求资源时间上的绝对顺序, 而非公平锁有可能刚释放锁的线程下次继续获取该锁,则有可能导致其他线程永远无法获取到锁,造成“饥饿”现象。

  • 公平锁为了保证时间上的绝对顺序,需要频繁的上下文切换, 而非公平锁会降低一定的上下文切换,降低性能开销。因此,ReentrantLock默认选择的是非公平锁,则是为了减少一部分上下文切换,保证了系统更大的吞吐量。

免费Java高级资料需要自己领取,涵盖了Java、Redis、MongoDB、MySQL、Zookeeper、Spring Cloud、Dubbo高并发分布式等教程,一共30G。
传送门:https://mp.weixin.qq.com/s/JzddfH-7yNudmkjT0IRL8Q

Java并发编程,深入理解ReentrantLock的更多相关文章

  1. Java 并发编程中使用 ReentrantLock 替代 synchronized 关键字原语

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

  2. Java并发编程笔记之ReentrantLock源码分析

    ReentrantLock是可重入的独占锁,同时只能有一个线程可以获取该锁,其他获取该锁的线程会被阻塞后放入该锁的AQS阻塞队列里面. 首先我们先看一下ReentrantLock的类图结构,如下图所示 ...

  3. Java并发编程示例代码-----ReentrantLock

    public class ReenterLock implements Runnable{ public static ReentrantLock lock=new ReentrantLock(); ...

  4. Java并发编程(三):ReentrantLock

    ReentrantLock是可以用来代替synchronized的.ReentrantLock比synchronized更加灵活,功能上面更加丰富,性能方面自synchronized优化后两者性能没有 ...

  5. Java并发编程总结3——AQS、ReentrantLock、ReentrantReadWriteLock(转)

    本文内容主要总结自<Java并发编程的艺术>第5章——Java中的锁. 一.AQS AbstractQueuedSynchronizer(简称AQS),队列同步器,是用来构建锁或者其他同步 ...

  6. java并发编程 | 锁详解:AQS,Lock,ReentrantLock,ReentrantReadWriteLock

    原文:java并发编程 | 锁详解:AQS,Lock,ReentrantLock,ReentrantReadWriteLock 锁 锁是用来控制多个线程访问共享资源的方式,java中可以使用synch ...

  7. Java并发编程总结3——AQS、ReentrantLock、ReentrantReadWriteLock

    本文内容主要总结自<Java并发编程的艺术>第5章——Java中的锁. 一.AQS AbstractQueuedSynchronizer(简称AQS),队列同步器,是用来构建锁或者其他同步 ...

  8. Java并发编程锁系列之ReentrantLock对象总结

    Java并发编程锁系列之ReentrantLock对象总结 在Java并发编程中,根据不同维度来区分锁的话,锁可以分为十五种.ReentranckLock就是其中的多个分类. 本文主要内容:重入锁理解 ...

  9. 【Java并发编程实战】-----“J.U.C”:ReentrantLock之三unlock方法分析

    前篇博客LZ已经分析了ReentrantLock的lock()实现过程,我们了解到lock实现机制有公平锁和非公平锁,两者的主要区别在于公平锁要按照CLH队列等待获取锁,而非公平锁无视CLH队列直接获 ...

  10. 【Java并发编程实战】-----“J.U.C”:ReentrantLock之一简介

    注:由于要介绍ReentrantLock的东西太多了,免得各位客官看累,所以分三篇博客来阐述.本篇博客介绍ReentrantLock基本内容,后两篇博客从源码级别分别阐述ReentrantLock的l ...

随机推荐

  1. 移动产品设计之ios系统的导航

    做道题:[不定项选择题] OS中导航设计模式有几种? A.平铺导航 B.标签导航 C.树形导航 D.模态视图导航 正确答案:A B C 讲解: 导航始终是产品设计的重头戏,往往产品设计中90%的事情就 ...

  2. docker资源汇总

    https://github.com/hangyan/docker-resources/blob/master/README_zh.md   https://github.com/lightning- ...

  3. xhEditor编辑器上传图片到 OSS

    前段时间,公司在项目上用到了xhEditor编辑器来给用户做一个上传图片的功能当时做的时候觉得很有意思,想想 基本的用户图片上传到自己服务器,还有点小占地方: 后来....然后直接上传到阿里云 .接下 ...

  4. Elementary OS上eclipse卡死问题

    解决: 1.可以用  sudo ./eclipse -vm /home/username/jdk_path/bin/java 启动但是启动后仍有显示问题. 2. 修改 eclipse.ini 在 -- ...

  5. linux kernel如何处理大端小端字节序

    (转)http://blog.csdn.net/skyflying2012/article/details/43771179 最近在做将kernel由小端处理器(arm)向大端处理器(ppc)的移植的 ...

  6. Makefile学习(二)----生成静态库文件

    Lunix下编译静态库文件: .o后缀文件:编译生成的中间代码文件: .a后缀文件:静态库文件,编译的时候会合到可执行程序中,文件比较大: .so后缀文件:动态库文件,只是一个指向,不会合到可执行程序 ...

  7. Atrenta电话面试(C++研发工程师)

    1.代码量是多少,你负责哪一块,工作量占%几,改进了什么   2.c++ 和 c 的 区别   3.list 和 vector 的 适用条件   4.hash_map 和 map 的 区别 , 使用h ...

  8. C#上位机开发(二)—— Hello,World

    上一篇大致了解了一下单片机实际项目开发中上位机开发部分的内容以及VS下载与安装,按照编程惯例,接下来就是“Hello,World!” 1.新建C#项目工程 首先选择新建Windows窗体应用(.NET ...

  9. Decorator(装饰器模式)

    装饰器模式允许我们根据运行时不同的情景动态地为某个对象调用前后添加不同的行为动作. <?php class HtmlTemplate { // any parent class methods ...

  10. 【LeetCode】Combination Sum(组合总和)

    这道题是LeetCode里的第39道题. 题目描述: 给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组 ...