摘要:为什么叫重入锁呢,我们把它拆开来看就明了了。释放锁,每次锁持有者数量递减,直到为止。
相信大家在工作或者面试过程中经常听到重入锁这个概念,或者与关键字 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 holds try { // ... 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://www.ucloud.cn/yun/75024.html
摘要:所谓的重入,就是当本线程想再次获得锁,不需要重新申请,它本身就已经锁了,即重入该锁。如果不为,则表示有线程已经占有了。总结回顾下要点是一个可重入的锁被当前占用的线程重入。 上一章《AQS源码阅读》讲了AQS框架,这次讲讲它的应用类(注意不是子类实现,待会细讲)。ReentrantLock,顾名思义重入锁,但什么是重入,这个锁到底是怎样的,我们来看看类的注解说明showImg(http:...
摘要:二什么是重入锁可重入锁,顾名思义,支持重新进入的锁,其表示该锁能支持一个线程对资源的重复加锁。将由最近成功获得锁,并且还没有释放该锁的线程所拥有。可以使用和方法来检查此情况是否发生。 一、写在前面 前几篇我们具体的聊了AQS原理以及底层源码的实现,具体参见 《J.U.C|一文搞懂AQS》《J.U.C|同步队列(CLH)》《J.U.C|AQS独占式源码分析》《J.U.C|AQS共享式源...
摘要:本文旨在对锁相关源码本文中的源码来自使用场景进行举例,为读者介绍主流锁的知识点,以及不同的锁的适用场景。中,关键字和的实现类都是悲观锁。自适应意味着自旋的时间次数不再固定,而是由前一次在同一个锁上的自旋时间及锁的拥有者的状态来决定。 前言 Java提供了种类丰富的锁,每种锁因其特性的不同,在适当的场景下能够展现出非常高的效率。本文旨在对锁相关源码(本文中的源码来自JDK 8)、使用场景...
摘要:自己实现在自己实现之前先搞清楚阻塞队列的几个特点基本队列特性先进先出。消费队列空时会阻塞直到写入线程写入了队列数据后唤醒消费线程。最终的队列大小为,可见线程也是安全的。 showImg(https://segmentfault.com/img/remote/1460000018811340); 前言 较长一段时间以来我都发现不少开发者对 jdk 中的 J.U.C(java.util.c...
摘要:所以通过设置一个适中的拉取注册表以及发送心跳的频率,保证大规模系统里对的请求压力不会太大。在注册表发生变更的时候会在内存中更新变更的注册表数据,同时过期掉。上述就是架构中,作为微服务注册中心可以承载大规模系统每天千万级访问量的原理。 欢迎关注微信公众号:石杉的架构笔记 周一至周五早8点!精品技术文章准时送上!! 往期文章1.拜托!面试请不要再问我Spring Cloud底层原理! 目...
阅读 1916·2021-11-23 09:51
阅读 1245·2019-08-30 15:55
阅读 1612·2019-08-30 15:44
阅读 758·2019-08-30 14:11
阅读 1145·2019-08-30 14:10
阅读 914·2019-08-30 13:52
阅读 2629·2019-08-30 12:50
阅读 614·2019-08-29 15:04