ReentrantLock实现机制
掌握Reentrantlock
具体结构
下文Reentrantlock简称RL,阅读之前强烈建议读一下AQS源码解析: https://www.cnblogs.com/seamount3/p/18690818
其实RL和AQS有关系,但不是直接有关系,是RL内部有一个Sync变量,RL其实是实现LOCK接口好来实现对应的LOCK方法
何为Sync,其实是一个内部类 extends AQS,内部又有两个子类分别是公平锁与非公平锁
RL的核心就是在对应的内部类Sync的子类上
子类之FairSync
lock
final void lock() {
acquire(1);
}
没太多好说的,其实就只是包装了一下,调用AQS的 acquire方法
相对有意思的就是为什么要是1?
1其实是AQS抽象出来的参数,在此地是代表线程请求锁时需要获取的许可数量
这里的 1 表示当前线程请求 一个 锁的许可,锁的操作是以许可为基础的。
具体看下面的tryAcquire
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;
}
}
相对简单,流程如下:
- 获取当前state变量
- state=0,判断CLH是否有节点
- 如果没有那么进行CAS操作state
- 操作成功的话,设置为独占线程
- state=0,判断CLH是否有节点
- 为了实现可重入,那么还要考虑是否独占线程为当前线程
- 是的话,int nextc = c + acquires;并且setState
子类之NonfairSync
lock
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
tryAcquire
一样不赘述
Sync父类实现了什么功能?
核心之tryRelease
本方法的实现是为了给AQS实现对应的钩子方法,在RL的unlock方法最终会调用AQS的release
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;
}
核心的流程如下:
- 判断当前线程是否是锁资源持有的线程
- 不是的话,抛异常
- 1ok后,修改state
- 如果state改完==0,那么彻底释放锁
- 如果不等于只是修改state,不释放锁,为了支持可重入嘛
如果面试官让介绍ReentrantLock如何介绍?
- 快速简单介绍(包括功能)
- 详细介绍下如何实现
快速简单介绍(包括功能)
首先ReentrantLock实现了对应的Lock接口,他的功能基本上起到的就是本地锁的作用,
ReentrantLock在功能上支持:
- 互斥性(RL是互斥锁,同一时刻只允许一个线程获取锁进入临界区,写操作自然也是互斥的。)
- 可重入性
- 公平与非公平
- 可中断,
lockInterruptibly()方法,允许线程在等待锁的过程中被中断 - 限时性,例如TryLock可以允许线程在指定的时间内尝试获取锁。如果在指定时间内没有获取到锁,线程会返回
false。
上述的功能大多是借助AQS的已有代码,以及ReentrantLock内部类像FairSync等继承了AQS并且实现了对应的钩子方法例如tryAcquire来实现总体的功能
详细介绍下如何实现
讲一下lock流程:
- 首先入口是RL的lock方法,而底层其实是调用内部变量Sync的acquire方法(也就是AQS的acquire模板方法)
- 这里就体现出公平与非公共的区别了,在构造器中我们会生成公平锁的实例或者非公平锁的实例通过这一点就实现了公平与非公平
- 以公平为例,那么我们会进行AQS的acquire流程
- 先调用对应公平锁实现的tryAcquire
- 获取当前state变量
- state=0,判断CLH是否有节点
- 如果没有那么进行CAS操作state
- 操作成功的话,设置为独占线程
- state=0,判断CLH是否有节点
- 为了实现可重入,那么还要考虑是否独占线程为当前线程
- 是的话,int nextc = c + acquires;并且setState
- 获取当前state变量
- 先调用对应公平锁实现的tryAcquire
- 如果tryAcquire失败,那么就进入把当前线程转换为Node添加到CLH队尾流程,然后等待唤醒,然后对应还有一个重要的方法就是acquireQueued,相当于是死循环,然后每个线程会再次tryAcquire如果失败再阻塞,之后就等待唤醒
讲一下unlock流程:
- 内部会调用对应Sync类的release方法(也就是AQS实现的模板方法)
- 然后执行对应的tryRelease流程
- 最后唤醒队列中的下一个节点
而刚刚提到的可中断也是AQS锁支持的,以及超时机制,都是AQS在特定代码,例如可中断则是在循环中会去判断下线程状态而超时则是在循环过程中结合当前时间与起始时间之间求差进行判断
ReentrantLock实现机制的更多相关文章
- Java并发编程基础-ReentrantLock的机制
同步锁: 我们知道,锁是用来控制多个线程访问共享资源的方式,一般来说,一个锁能够防止多个线程同时访问共享资源,在Lock接口出现之前,Java应用程序只能依靠synchronized关键字来实现同步锁 ...
- ReentrantLock原理学习
上文我们学习了ReentrantLock的基本用法,在最后我们留下了一个问题,ReentrantLock获取的锁是什么锁呢?本文我们就从源码的角度来一探究竟.本文涉及到的源码对应JDK版本为1.8. ...
- Synchronize和ReentrantLock区别
转自:https://blog.csdn.net/m0_37700275/article/details/83151850 目录介绍1.Synchronize和ReentrantLock区别 1.1 ...
- [转] 多线程 《深入浅出 Java Concurrency》目录
http://ifeve.com/java-concurrency-thread-directory/ synchronized使用的内置锁和ReentrantLock这种显式锁在java6以后性能没 ...
- 阿里,百度面试90%会问的Java面试题
题目一 请对比 Exception 和 Error,另外,运行时异常与一般异常有什么区别? 考点分析: 分析 Exception 和 Error 的区别,是从概念角度考察了 Java 处理机制.总的来 ...
- BATJ等公司必问的8道Java经典面试题,你都会了吗?
1.谈谈你对 Java 平台的理解?“Java 是解释执行”,这句话正确吗? 考点分析: 对于这类笼统的问题,你需要尽量表现出自己的思维深入并系统化,Java 知识理解得也比较全面,一定要避免让面试官 ...
- 《深入浅出 Java Concurrency》目录
最近在学习J.U.C,看到一个大神 关于这个系列写的非常精辟,由于想做笔记,故系列转载并记录之. 原文:http://www.blogjava.net/xylz/archive/2010/07/08/ ...
- Java之美[从菜鸟到高手演变]系列之博文阅读导航
随着博文越来越多,为博客添加一个导航很有必要!本博客将相继开通Java.CloudFoundry.Linux.Ruby等专栏,都会设立目录,希望读者朋友们能更加方便的阅读! 在阅读的过程中有任何问题, ...
- Java并发编程--3.Lock
Lock接口 它提供3个常用的锁 lock() : 获不到锁就就一直阻塞 trylock() :获不到锁就立刻放回 或者 定时的,轮询的获取锁 lockInterruptibly() : 获不到锁时阻 ...
- BAT等公司必问的8道Java经典面试题,你都会了吗?
工作多年以及在面试中,我经常能体会到,有些面试者确实是认真努力工作,但坦白说表现出的能力水平却不足以通过面试,通常是两方面原因: 1.“知其然不知其所以然”.做了多年技术,开发了很多业务应用,但似乎并 ...
随机推荐
- P8392 BalticOI 2022 Day1 Uplifting Excursion
P8392 BalticOI 2022 Day1 Uplifting Excursion 贪心加动规,好题,这两个甚至完全相反的东西可以融进一道题-- 思路 物品较少,贡献较小,体积较小,但总体积巨大 ...
- docker番外篇-最详细的安装及部署项目教程(net framework,netcore,java,nodejs,静态html,mysql,redis,私有仓库,https免费证书等)
目录 本地widows(win11)docker环境安装 安装Docker Desktop 服务器liunx(ubuntu)docker环境安装 安装nginx 安装docker环境 安装docker ...
- PHP扩展之Yaconf
这个是继鸟哥出品的yaf,yar 之后的又一个好用的工具. Yaconf配置管理工具 具体可以看鸟哥的文档: https://www.laruence.com/2015/06/12/3051.htm ...
- php之编译安装
1. 安装所需环境 yum -y install libxml2 libxml2-devel openssl openssl-devel curl-devel libjpeg-devel libpng ...
- The 2023 ICPC Asia Hong Kong Regional Programming Contest
The 2023 ICPC Asia Hong Kong Regional Programming Contest A. TreeScript 给你一个根,让你构造一棵树,每个节点被创造的时候必须知道 ...
- manim边做边学--曲面
Surface类是Manim中专为创建和操控复杂的三维表面而打造的. 在实际应用中,无论是创建数学教学中的几何模型,还是模拟物理现象中的曲面变化,甚至是构建复杂的动画场景中的三维元素,Surface类 ...
- 《JavaScript 模式》读书笔记(8)— DOM和浏览器模式1
在本书的前面章节中,我们主要集中关注于核心JavaScript(ECMAScript),而并没有太多关注在浏览器中使用JavaScript的模式.本章将探索一些浏览器特定的模式,因为浏览器是使用Jav ...
- Git因换行符不一致导致反复有修改记录
前情 Git(读音为/gɪt/)是一个开源的分布式版本控制系统,可以有效.高速地处理从很小到非常大的项目版本管理,我公司目前都是基于Git来管理项目代码. 坑位 最近刚刚入职一家新公司,本地环境都配好 ...
- C#调用Python脚本的方式(一),以PaddleOCR-GUI为例
前言 每种语言都有每种语言的优势,Python由于其强大的生态,很多任务通过调用包就可以实现,那么学会从C#项目中调用Python脚本完成任务就很重要.C#调用Python代码有多种方式,如果Pyth ...
- ABAP开发规范V1.0
1. 概要 1.1目的 该文档定义了在开发与维护ABAP程序过程中必须遵守的规范与标准.该文档应当被视为一个动态的文档,该文档会根据需要进行增补和修订. 开发规范的重要作用在于保持整个开发团队的开发风 ...