ReentrantLock 重入锁简介

重入锁 ReentrantLock,顾名思义,就是支持同一个线程对资源的重复加锁。另外,该锁还支持获取锁时的公平与非公平性的选择。

重入锁 ReentrantLock,只支持独占方式的获取操作,因此它只实现了 tryAcquire、tryRelease 和 isHeldExclusively 方法。

ReentrantLock 如何实现锁重入

锁重入是指任意线程在获取到锁之后,能够再次获取该锁而不会被锁所阻塞,该特性的实现需要解决两个问题:

1、线程再次获取锁

需要识别获取锁的线程是否为当期占有锁的线程,如果是,则便获取锁成功

2、锁最终得到释放

同一个线程重复 n 次获得了锁,在第 n 次释放该锁后,其它线程能够获取到该锁。锁的最终释放要求锁对于获取进行计数,计数表示当前锁被重复获取的次数,而锁被释放时,计数自减,当计数等于0时,表示锁已经成功释放


ReentrantLock 是通过自定义同步器来实现所得获取和释放,默认使用非公平性,下面就以非公平性获取锁为例,学习重入锁是如何实现的:

 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) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}

通过判断当前线程是否为获取锁的线程来决定获取操作是否成功,如果是获取锁的线程,则将同步状态值进行累加并返回true,表示获取同步状态成功。

成功获取锁的线程再次获取锁,只是增加了同步状态值,这也就要求在释放同步状态时递减同步状态的值。如下,释放锁的代码:

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

如果该锁被获取了n次, 那么前( n- 1) 次 tryRelease( int releases) 方法必须返回false,只有同步状态完全释放了,才能返回tru。 该方法将同步状态 是否为 0 作为作为最终释放的条件,当同步状态为0时,将该锁的拥有者线程设置为null,并返回true,表示成功释放。

ReentrantLock 如何实现锁的公平性与非公平性

公平性与否是针对获取锁而言的,如果一个锁时公平的,那么锁的获取顺序就应该服务请求时间的顺序,也就是FIFO。

由上文介绍的非公平获取锁方法 nonfairTryAcquire( int acquires) 可知,只要CAS设置同步状态成功,则表示线程获取了锁,而公平锁则不同,如代码所示:

static final class FairSync extends Sync {

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( int acquires) 的区别在于多了hasQueuedPredecessors() 方法,即加入了同步队列中当前节点是否有前驱节点的判断,如果该方法返回true,则表示有线程比当前线程更早的请求了锁,因此需要等待前驱线程获取并释放锁之后才能继续获取锁。

Java 显示锁 之 重入锁 ReentrantLock(七)的更多相关文章

  1. 浅谈Java中的公平锁和非公平锁,可重入锁,自旋锁

    公平锁和非公平锁 这里主要体现在ReentrantLock这个类里面了 公平锁.非公平锁的创建方式: //创建一个非公平锁,默认是非公平锁 Lock lock = new ReentrantLock( ...

  2. java面试-公平锁/非公平锁/可重入锁/递归锁/自旋锁谈谈你的理解

    一.公平锁/非公平锁/可重入锁/递归锁/自旋锁谈谈你的理解 公平锁:多个线程按照申请的顺序来获取锁. 非公平锁:多个线程获取锁的先后顺序与申请锁的顺序无关.[ReentrantLock 默认非公平.s ...

  3. 可重入锁 & 不可重入锁

    可重入锁指同一个线程可以再次获得之前已经获得的锁,避免产生死锁. Java中的可重入锁:synchronized 和 java.util.concurrent.locks.ReentrantLock. ...

  4. 二、多线程基础-乐观锁_悲观锁_重入锁_读写锁_CAS无锁机制_自旋锁

    1.10乐观锁_悲观锁_重入锁_读写锁_CAS无锁机制_自旋锁1)乐观锁:就像它的名字一样,对于并发间操作产生的线程安全问题持乐观状态,乐观锁认为竞争不总是会发生,因此它不需要持有锁,将 比较-设置 ...

  5. redis分布式锁-可重入锁

    redis分布式锁-可重入锁 上篇redis实现的分布式锁,有一个问题,它不可重入. 所谓不可重入锁,即若当前线程执行某个方法已经获取了该锁,那么在方法中尝试再次获取锁时,就会获取不到被阻塞. 同一个 ...

  6. Java多线程系列——深入重入锁ReentrantLock

    简述 ReentrantLock 是一个可重入的互斥(/独占)锁,又称为“独占锁”. ReentrantLock通过自定义队列同步器(AQS-AbstractQueuedSychronized,是实现 ...

  7. java线程的同步控制--重入锁ReentrantLock

    我们常用的synchronized关键字是一种最简单的线程同步控制方法,它决定了一个线程是否可以访问临界区资源.同时Object.wait() 和Object.notify()方法起到了线程等待和通知 ...

  8. Java并发包4--可重入锁ReentrantLock的实现原理

    前言 ReentrantLock是JUC提供的可重入锁的实现,用法上几乎等同于Synchronized,但是ReentrantLock在功能的丰富性上要比Synchronized要强大. 一.Reen ...

  9. Java并发编程-可重入锁

    可重入锁,也叫做递归锁,指的是同一线程 外层函数获得锁之后 ,内层递归函数仍可以获取该锁而不受影响.在JAVA环境下 ReentrantLock 和synchronized 都是 可重入锁. publ ...

随机推荐

  1. 泛型约束:接口约束、new()构造函数约束、组合约束(即多种约束合并)

    泛型 接口约束: using System; namespace ConsoleApp1 { /* * * 接口约束:where T:interfaceName * T是类型形参的名称,interfa ...

  2. MUI 结合layui实现分页

    mui自带有分页,在ui上我还是认为layui的友好点. 第三方插件: template-web.js-----------------前端数据绑定 layui.js.layui.css------- ...

  3. jumperver源码理解以及部分修改

    一  admin后台处理以及展示修改    jumpserver 默认不开放admin后台(获取是我没用使用正确的打开方式,) 打开方式 找到程序的入口 urls.py 修改,另外主要看下settin ...

  4. Mac下使用Charles抓包https接口

    1 官方网站下载,安装好Charles https://www.charlesproxy.com/download/ 2 安装ssl证书 3 信任证书 4 手机iPhone配置 ,获取证书url 5 ...

  5. 树的总结(遍历,BST,AVL原型,堆,练习题)

    目录 树 一.抽象数据类型 二.二叉树的性质 三.二叉树的遍历 三.活用树的遍历 四.BST树 五.AVL树 六.BST树和AVL树练习 七.堆 树 @ 一.抽象数据类型 1.顺序存储 使用数组存储 ...

  6. python3:iterable, iterator, generator,抽象基类, itertools的使用。

    目录: iterable对象 iterator对象, 数据类型Iterator类 数据类型Generator类. 生成器表达式 collections.abc:容器的抽象基类.用于判断具体类. ite ...

  7. JavaScript教程——实例对象与 new 命令

    典型的面向对象编程语言(比如 C++ 和 Java),都有“类”(class)这个概念.所谓“类”就是对象的模板,对象就是“类”的实例.但是,JavaScript 语言的对象体系,不是基于“类”的,而 ...

  8. 使用EntityFramework6连接MySql数据库-db first方式

    准备工具: VS2013.MySQL For VisualStudio 1.1.4.Connector/Net 6.8.3 程序包管理器执行命令: Install-Package EntityFram ...

  9. Codeforces Round #589 (Div. 2) E. Another Filling the Grid(DP, 组合数学)

    链接: https://codeforces.com/contest/1228/problem/E 题意: You have n×n square grid and an integer k. Put ...

  10. pip command not found

    [root@ Python-2.7.9]# pip install jinja2 -bash: pip: command not found 解决 [root@ ~]#  yum -y install ...