文档章节

轻松学习java可重入锁(ReentrantLock)的实现原理

天王盖地虎626
 天王盖地虎626
发布于 06/19 17:44
字数 1714
阅读 2
收藏 0

前言

相信学过java的人都知道 synchronized 这个关键词,也知道它用于控制多线程对并发资源的安全访问,兴许,你还用过Lock相关的功能,但你可能从来没有想过java中的锁底层的机制是怎么实现的。如果真是这样,而且你有兴趣了解,今天我将带领你轻松的学习下java中非常重要,也非常基础的可重入锁-ReentrantLock的实现机制。
听故事把知识掌握了

在一个村子里面,有一口井水,水质非常的好,村民们都想打井里的水。这井只有一口,村里的人那么多,所以得出个打水的规则才行。村长绞尽脑汁,最终想出了一个比较合理的方案,咱们来仔细的看看聪明的村长大人的智慧。

井边安排一个看井人,维护打水的秩序。

打水时,以家庭为单位,哪个家庭任何人先到井边,就可以先打水,而且如果一个家庭占到了打水权,其家人这时候过来打水不用排队。而那些没有抢占到打水权的人,一个一个挨着在井边排成一队,先到的排在前面。打水示意图如下 :

是不是感觉很和谐,如果打水的人打完了,他会跟看井人报告,看井人会让第二个人接着打水。这样大家总都能够打到水。是不是看起来挺公平的,先到的人先打水,当然不是绝对公平的,自己看看下面这个场景 :

看着,一个有娃的父亲正在打水,他的娃也到井边了,所以女凭父贵直接排到最前面打水,羡煞旁人了。
以上这个故事模型就是所谓的公平锁模型,当一个人想到井边打水,而现在打水的人又不是自家人,这时候就得乖乖在队列后面排队。

事情总不是那么一帆风顺的,总会有些人想走捷径,话说看井人年纪大了,有时候,眼力不是很好,这时候,人们开始打起了新主意。新来打水的人,他们看到有人排队打水的时候,他们不会那么乖巧的就排到最后面去排队,反之,他们会看看现在有没有人正在打水,如果有人在打水,没辄了,只好排到队列最后面,但如果这时候前面打水的人刚刚打完水,正在交接中,排在队头的人还没有完成交接工作,这时候,新来的人可以尝试抢打水权,如果抢到了,呵呵,其他人也只能睁一只眼闭一只眼,因为大家都默认这个规则了。这就是所谓的非公平锁模型。新来的人不一定总得乖乖排队,这也就造成了原来队列中排队的人可能要等很久很久。

java可重入锁-ReentrantLock实现细节

ReentrantLock支持两种获取锁的方式,一种是公平模型,一种是非公平模型。在继续之前,咱们先把故事元素转换为程序元素。

咱们先来说说公平锁模型:

初始化时, state=0,表示无人抢占了打水权。这时候,村民A来打水(A线程请求锁),占了打水权,把state+1,如下所示:

线程A取得了锁,把 state原子性+1,这时候state被改为1,A线程继续执行其他任务,然后来了村民B也想打水(线程B请求锁),线程B无法获取锁,生成节点进行排队,如下图所示:

初始化的时候,会生成一个空的头节点,然后才是B线程节点,这时候,如果线程A又请求锁,是否需要排队?答案当然是否定的,否则就直接死锁了。当A再次请求锁,就相当于是打水期间,同一家人也来打水了,是有特权的,这时候的状态如下图所示:

到了这里,相信大家应该明白了什么是可重入锁了吧。就是一个线程在获取了锁之后,再次去获取了同一个锁,这时候仅仅是把状态值进行累加。如果线程A释放了一次锁,就成这样了:

仅仅是把状态值减了,只有线程A把此锁全部释放了,状态值减到0了,其他线程才有机会获取锁。当A把锁完全释放后,state恢复为0,然后会通知队列唤醒B线程节点,使B可以再次竞争锁。当然,如果B线程后面还有C线程,C线程继续休眠,除非B执行完了,通知了C线程。注意,当一个线程节点被唤醒然后取得了锁,对应节点会从队列中删除。

非公平锁模型

如果你已经明白了前面讲的公平锁模型,那么非公平锁模型也就非常容易理解了。当线程A执行完之后,要唤醒线程B是需要时间的,而且线程B醒来后还要再次竞争锁,所以如果在切换过程当中,来了一个线程C,那么线程C是有可能获取到锁的,如果C获取到了锁,B就只能继续乖乖休眠了。这里就不再画图说明了。

其它知识点

java5中添加了一个并发包, java.util.concurrent,里面提供了各种并发的工具类,通过此工具包,可以在java当中实现功能非常强大的多线程并发操作。对于每个java攻城狮,我觉得非常有必要了解这个包的功能。虽然做不到一步到位,但慢慢虚心学习,沉下心来,总能慢慢领悟到java多线程编程的精华。

结束语

可重入锁的实现会涉及到CAS,AQS,java内存可见性(volatile)等知识,为了避免大家直接被代码搞晕,故而想以最简单的方式把可重入锁进行抽象,讲明白其中的实现原理,这样看起源码也有个借鉴的思路,希望本篇能够帮助到你们。
---------------------  
 

本文转载自:https://blog.csdn.net/yanyan19880509/article/details/52345422/

天王盖地虎626

天王盖地虎626

粉丝 32
博文 527
码字总数 20708
作品 0
南京
私信 提问
Java中的公平锁和非公平锁实现详解

前言 ReentrantLock的可重入性分析 synchronized的可重入性 ReentrantLock的可重入性 ReentrantLock锁的实现分析 公平锁和非公平锁 公平锁FairSync 非公平锁NonfairSync ReentrantLock锁的释...

kim_o
2018/06/08
59
0
到底什么是重入锁,拜托,一次搞清楚!

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

Java技术栈
06/27
79
0
轻松学习java可重入锁(ReentrantLock)的实现原理

前言 相信学过java的人都知道 synchronized 这个关键词,也知道它用于控制多线程对并发资源的安全访问,兴许,你还用过Lock相关的功能,但你可能从来没有想过java中的锁底层的机制是怎么实现...

onedotdot
2017/10/31
8
0
CountDownLatch源码解析

CountDownLatch 相比ReentranceLock,CountDownLatch的流程还是相对比较简单的,CountDownLatch也是基于AQS,它是AQS的共享功能的一个实现。 下面从源代码的实现上详解CountDownLatch。 1、C...

maxam0128
2018/01/23
0
0
Java锁的种类以及辨析(四):可重入锁

作者:山鸡 锁作为并发共享数据,保证一致性的工具,在JAVA平台有多种实现(如 synchronized 和 ReentrantLock等等 ) 。这些已经写好提供的锁为我们开发提供了便利,但是锁的具体性质以及类型...

onedotdot
2017/11/01
24
0

没有更多内容

加载失败,请刷新页面

加载更多

CSS--列表

一、列表标识项 list-style-type none:去掉标识项 disc:默认实心圆 circle:空心圆 squire:矩形 二、列表项图片 list-style-img: 取值:url(路径) 三、列表项位置 list-style-position:...

wytao1995
今天
6
0
linux 命令-文本比较comm、diff、patch

本文原创首发于公众号:编程三分钟 今天学了三个文本比较的命令分享给大家。 comm comm 命令比较相同的文本 $ cat charabc$ cat chardiffadc 比如,我有两个文件char和chardiff如上,...

编程三分钟
今天
7
0
QML教程

https://blog.csdn.net/qq_40194498/article/category/7580030 https://blog.csdn.net/LaineGates/article/details/50887765...

shzwork
今天
5
0
HA Cluster之5

对于使用heartbeat v2版的CRM配置的集群信息都是保存在一个名为cib.xml的配置文件中,存放在/var/lib/heartbeat/crm/下。CIB:Cluster Information Base,由于xml文件配置不是那么方便,所以...

lhdzw
今天
6
0
玩转Redis-Redis基础数据结构及核心命令

  《玩转Redis》系列文章主要讲述Redis的基础及中高级应用,文章基于Redis5.0.4+。本文主要讲述Redis的数据结构String,《玩转Redis-Redis基础数据结构及核心命令》相关操作命令为方便对比...

zxiaofan666
今天
11
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部