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. 响应式Web设计- Viewport

    什么是Viewport? viewport是用户网页的可视区域, 翻译为中文可以叫做"视区". 设置Viewport 一个常用的针对移动网页优化过的页面的Viewport meta ...

  2. Linux关于FTP安全

    https://www.cnblogs.com/Hyber/archive/2017/02/04/6362916.htmlhttps://www.cnblogs.com/ichunqiu/p/7300 ...

  3. Ubuntu 下的aegisub安装

    大家用开源的软件用习惯了.推荐大家使用一下字幕编辑软件 分享的是Ubuntu下的安装教程: $ sudo add-apt-repository ppa:djcj/aegisub $ sudo apt- ...

  4. pytorch导入错误so: undefined symbol: _Z11libshm_initPKc

    首先删除torch文件 或者直接卸载 删除会更彻底 https://blog.csdn.net/qq_37674858/article/details/88870124 但是会发现卸载重装pytorc ...

  5. The US in understimating Huawei, says founder Ren zhengfei

    Huawei Founder Ren Zhengfei has downplayed the impact of the US executive order that cripple Huawei' ...

  6. 创建安卓模拟器的两种方式及常用Android命令介绍

    创建安卓模拟器有以下两种方式: 1>通过图形界面创建,在Eclipse中单击Windows->Android Virtual Device Manager启动图形界面窗口 2>如果用 ...

  7. 【12】link与@import的区别

    [12]link与@import的区别 link是HTML方式, @import是CSS方式 link最大限度支持并行下载,@import过多嵌套导致串行下载,出现FOUC link可以通过rel=& ...

  8. Fatal error: Call to a member function rowCount() on a non-object in /opt/lampp/htdocs/xampp/assets/update.php on line 6

    $sql = "SELECT * from idea ORDER BY datetime DESC LIMIT 50;"; $result = $pdo->query($sq ...

  9. [BZOJ4506] [Usaco2016 Jan]Fort Moo(DP?)

    传送门 总之可以先预处理出来每个位置最多往上延伸多少 枚举两行,看看夹在这两行中间的列最大能构成多大的矩形 可以看出,必须得在一个两行都没有X的区间才有可能构成最大的答案 那么可以把这些区间处理出来, ...

  10. 【离散化树状数组】Nordic Collegiate Programming Contest G.Galactic Collegiate Programming Contest

    #include<bits/stdc++.h> using namespace std; typedef long long ll; int n,m; ; struct node { in ...