到底什么是重入锁,拜托,一次搞清楚!

article/2025/10/14 0:19:51

相信大家在工作或者面试过程中经常听到重入锁这个概念,或者与关键字 synchrozied 的对比,栈长面试了这么多人,80%的面试者都没有答对或没有答到点上,或者把双重效验锁搞混了,哭笑不得。。

那么你对重入锁了解有多少呢?今天,栈长帮大家撕开重入锁的面纱,来见识下重入锁的真实容颜。。

什么是重入锁

java.util.concurrent.locks.ReentrantLock

这个是 JDK @since 1.5 添加的一种颗粒度更小的锁,它完全可以替代 synchronized 关键字来实现它的所有功能,而且 ReentrantLock 锁的灵活度要远远大于 synchronized 关键字。

从类结构图看出,ReentrantLock 实现了 Lock 接口,ReentrantLock 只是 Lock 接口的一个实现而已。

java.util.concurrent.locks.Lock

它们都是 java.util.concurrent 包里面的内容(俗称 JUC、并发包),也都是 JDK 1.5 开始加入的。

为什么叫重入锁呢?

ReentrantLock,我们把它拆开来看就明了了。

Re-Entrant-Lock:即表示可重新反复进入的锁,但仅限于当前线程;


public void m() {lock.lock();lock.lock();try {// ... method body} finally {lock.unlock()lock.unlock()}}

如示例代码所示,当前线程可以反复加锁,但也需要释放同样加锁次数的锁,即重入了多少次,就要释放多少次,不然也会导入锁不被释放。

试想一下,如果不设计成可重入锁,那自己如果反复给自己加锁,不是会把自己加死锁了吗?所以,到现在,重入锁的概念大概应该清楚了吧?

重入锁最重要的几个方法

这几个方法都是 Lock 接口中定义的:

1)lock()

获取锁,有以下三种情况:

  • 锁空闲:直接获取锁并返回,同时设置锁持有者数量为:1;

  • 当前线程持有锁:直接获取锁并返回,同时锁持有者数量递增1;

  • 其他线程持有锁:当前线程会休眠等待,直至获取锁为止;

2)lockInterruptibly()

获取锁,逻辑和 lock() 方法一样,但这个方法在获取锁过程中能响应中断。

3)tryLock()

从关键字字面理解,这是在尝试获取锁,获取成功返回:true,获取失败返回:false, 这个方法不会等待,有以下三种情况:

  • 锁空闲:直接获取锁并返回:true,同时设置锁持有者数量为:1;

  • 当前线程持有锁:直接获取锁并返回:true,同时锁持有者数量递增1;

  • 其他线程持有锁:获取锁失败,返回:false;

4)tryLock(long timeout, TimeUnit unit)

逻辑和 tryLock() 差不多,只是这个方法是带时间的。

5)unlock()

释放锁,每次锁持有者数量递减 1,直到 0 为止。所以,现在知道为什么 lock 多少次,就要对应 unlock 多少次了吧。

6)newCondition

返回一个这个锁的 Condition 实例,可以实现 synchronized 关键字类似 wait/ notify 实现多线程通信的功能,不过这个比 wait/ notify 要更灵活,更强大!

重入锁大概的用法


class X {private final ReentrantLock lock = new ReentrantLock();// ...public void m() {lock.lock();  // block until condition holdstry {// ... method body} finally {lock.unlock()}}}}

看见没有,加锁和释放锁都在方法里面进行,可以自由控制,比 synchronized 更灵活,更方便。但要注意的是,释放锁操作必须在 finally 里面,不然如果出现异常导致锁不能被正常释放,进而会卡死后续所有访问该锁的线程。

synchronized 是重入锁吗?

那么问题来了,synchronized 是重入锁吗?

你可能会说不是,因为 ReentrantLock 既然是重入锁,根据推理,相反,那 synchronized 肯定就不是重入锁,那你就错了。

答案是:yes,为什么?看下面的例子:


public synchronized void operation(){add();}public synchronized void add(){}

operation 方法调用了 add 方法,两个方法都是用 synchronized 修饰的,add() 方法可以成功获取当前线程 operation() 方法已经获取到的锁,说明 synchronized 就是可重入锁。

面试常问的Synchronized的几种用法推荐看下这篇文章:Synchronized 有几种用法?。

总结

今天,重入锁就大概写到这里了,其实重入锁就是一种颗粒度更小的锁,控制更方便,更强大,栈长只是简单介绍一下重入锁的基本概念及用法,但远不止这么简单,还有很多,一篇也难也详尽,够写好多篇了。

大家也可以关注微信公众号:Java技术栈,栈长将继续分享更多重入锁的高级的概念及工作中的实战用法,请关注后续文章,或者在公众号后台回复:多线程,栈长已经整理好了许多 Java 多线程系列文章,都是接地气干货。

觉得有用,转发分享下朋友圈给更多的人看吧,另外,给个好看,谢谢老板~

关注Java技术栈微信公众号,栈长将继续分享 Java 干货教程,公众号第一时间推送,持续关注。在公众号后台回复:java,获取栈长整理的更多的 Java 教程,都是实战干货,以下仅为部分预览。

  • 你真的搞懂 transient 关键字了吗?

  • 面试常考:Synchronized 有几种用法?

  • Java 11 已发布,String 还能这样玩!

  • Java 中的 String 真的是不可变吗?

  • sleep( ) 和 wait( ) 的这 5 个区别

  • ……

本文原创首发于微信公众号:Java技术栈(id:javastack),转载请原样保留本信息。

转载于:https://my.oschina.net/javaroad/blog/3066647


http://chatgpt.dhexx.cn/article/Y2DNCI5U.shtml

相关文章

重入锁-ReentrantLock

ReentrantLock 一.重入锁的特点1)实现重进入功能2)分为公平锁和非公平锁: 二.ReentrantLock和AQS的关系 一.重入锁的特点 1)实现重进入功能 重进入是指任意线程获取锁之后能够再次获取该锁而不会被锁阻塞 锁的获取和释放过程如下: 线程再次获取锁。锁…

详述重入锁-ReentrantLock

什么是重入锁? 锁主要用来控制多线程访问的行为,对于同一个线程,如果连续两次对同一把锁进行lock,那么这个线程会被卡死在那里,这样的特性很不好,在实际的开发中,方法之间的调用方式错综复杂&a…

进行LDPC编码时扔掉了前面2Zc的信息位,为何如此设计?在解码时如何恢复?

好久没发文章了,拿去年的周报水一篇吧。 其实我也不是研究LDPC的,就是之前被导师提过这个问题,就看了一阵子。下面进入正文—— LDPC基础概念 对于这个问题,还是需要对LDPC码有初步的了解,下面先由一个普通的规则LDPC…

基于matlab的ldpc编码的构造,基于LDPC编码的GMSK调制与解调及matlab仿真实现(含录像)...

基于LDPC编码的GMSK调制与解调及matlab仿真实现(含录像)(开题报告,论文10700字,程序代码,录像) 摘 要 随着无线通信技术的不断发展与进步,数字电视广播、移动视频点播等对数据吞吐量要求很高的业务逐渐变得可能。为了在有限的带宽内用有限的发射功率保证信息在空间传…

ldpcMATLAB/ldpc的译码,matlab程序/LDPC编码的matlab实现/源码

ldpcMATLAB/ldpc的译码,matlab程序/LDPC编码的matlab实现/源码 1、ldpcMATLAB(ldpc编码的MATLAB例子,内容相对来说还是比较详细的。值得参考借鉴。) 2、LDPCmatlab(LDPC码的matlab实现,把解码的部分改过了&#xff…

通信算法之四十:5G NR LDPC编码译码性能仿真

1.码率1/5,增益14dB 2.码率1/12,增益17.8dB [ 相应MATLAB仿真代码。咨询qq:1279682290 ]

DVB-S2系统中LDPC译码器的实现 LDPC编码器的实现 FPGA DVB-S2、DVB-S2X LDPC 编码IP、LDPC译码 IP

DVB S2 LDPC 译码器.IP core IP Core特点: 1.全部代码由FPGA代码实现; 2.支持DVB-S2、DVB-S2X全部格式; 3.支持编码、译码; 4.支持标标准中16200、32400、64800三种帧长; 5.支持ACM、VCM、CCM模式,参…

UCI和数据复用在pusch上传输(第六部分)---ldpc编码

ldpc编码针对的是上下行数据的编码,也是5G最重要的一种编码。 1 TB块添加CRC 这个是和UCI POLAR区别的一个地方,UCI是对每个cb块添加crc. % Get transport block size after CRC attachment according to 38.212% 6.2.1 and 7.2.1, and assign CRC po…

【编码译码】基于matlab实现LDPC编码和解码

✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,matlab项目合作可私信。 🍎个人主页:Matlab科研工作室 🍊个人信条:格物致知。 更多Matlab仿真内容点击👇 智能优化算法 …

【LDPC编码】CDR系统中LDPC编码,LDPC编码的码长为9216

1.软件版本 matlab2013b 2.系统描述 在广播通信系统中,消息发送的速度和性能是一对矛盾,当发送速度快,则必然会降低消息的可靠性,当要求系统的性能,则必然会降低发送码率。为了提高系统的性能,并尽可能的…

5G LDPC编码流程

参照3GPP的标准文档,摘录其中下行共享信道与寻呼信道的LDPC编码流程,以便于进行对应的软件仿真 传输块加CRC校验   记待传输的数据块序列为 a 0 , a 1 , ⋯ , a A − 1 a_0,a_1,\cdots,a_{A-1} a0​,a1​,⋯,aA−1​,其中 A A A为传输块的负…

linux杀进程

linux学习心得 查看所有进行中的后台进程 命令 :ps aux ps命令查看应用进程。 后面的参数 -a : 显示现行终端机下的所有进程,包括其他用户的进程; -u :以用户为主的进程状态 ; x :通常与 a …

Linux找到进程并杀死

第一种情况: 写脚本的时候没没把程序杀死,再次启动发现端口被占用了,于是找到原来的端口然后kill掉重启 用下面2个命令可以: netstat -tunlp|grep 8080t:表示查看tcp u:表示查看udp n:表示端口…

在 Linux 中杀死一个进程

在 Linux 中,假如一个进程的 PID 为 3810,那么结束一个进程可以使用如下命令: $ kill -9 3810 以 Postman 为例,首先我们需要找到它的进程号,然后才能杀死。 查找进程号使用 ps 命令,不过有一个强大的参…

Linux命令行下杀死一个进程

在做项目的时候经常会出现程序死机、锁死、无响应等情况,这时候就需要找到程序相应的进程将其杀掉即可。步骤如下: 1.定位进程 top命令:可以实时动态地查看系统的整体运行情况,是一个综合了多方信息监测系统性能和运行信息的实用…

linux中进程杀不死解决办法

如图,多次在kill -9 此进程后依然存在 先说解决办法,输入过滤命令ps -ef|grep xxx(此处写要过滤的进程名字),例如 之后kill掉对应的进程号,如图 问题解决。 如果有多个子进程可以先过滤再一起杀死&#xf…

Linux中kill命令杀不掉进程的解决办法

1、进程杀不掉的原因有两种: (1)这个进程是僵尸进程 ; (2)此进程是"核心态"进程。 2、解决办法: (1)进入到“/proc/进程号”目录下,执行“cat stat…

Linux 批量杀进程

1.查需要杀死的进程 ps -ef | grep yum 2.去除掉里面的grep ps -ef | grep yum | grep -v grep 3.打印kill命令 ps -ef | grep yum | grep -v grep | awk {print "kill "$2} 4.执行kill命令 ps -ef | grep yum | grep -v grep | awk {print "kill "$2} …

linux 找出谁杀了进程

目录 Linux Signal 到底是什么信号 OOM 谁发的信号 systemtap audit 案例与总结 服务端的程序,一般都希望比较长时间的运行,比如7*24小时。不过,程序也需要更新,比如修Bug,比如增加新功能,比如修复增…

Linux操作系统之批量杀死进程

前言 在Linux操作系统中,一般常用的杀死进程的命令是 kill 、 pkill 、 killall ,根据杀死单个进程拓展至批量杀死进程。 1、查看指定名称的进程,如下查看运行wps程序的进程: ps -ef | grep wps | grep -v grep 结果如下&…