java 可重入锁ReentrantLock的介绍

时间:2021-05-25 18:21:02

一个小例子帮助理解(我们常用的synchronized也是可重入锁)

话说从前有一个村子,在这个村子中有一口水井,家家户户都需要到这口井里打水喝。由于井水有限,大家只能依次打水。为了实现家家有水喝,户户有水用的目标,村长绞尽脑汁,最终想出了一个比较合理的方案。

首先,在水井边上安排一个看井人,负责维持秩序。

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

最后,打水的人打完水以后就告诉看井人,看井人就让等待的队伍中的最前面一个去打水。

这样一来,大家都能打到水,也保证了相对的公平。这就是公平锁的基本思路。

随着时间的推移,村民发现每次去打水的时候都需要排队,想着每次排队都浪费时间,于是就把水桶放在井边代替,自己则溜回家去了。这样一搞,可把看井人累坏,经常往村民家里跑,让他们来打水。于是聪明的看井人想出了一个对策,如果有人打完水后,刚好又有其它人来打水,就直接让这个新来的人上去打水,不用到队伍末尾去排队等候。

这种方式虽然看上去不公平,但是他节省了资源,提高了打水的性能,这就是非公平锁的基本思路。

打水的小故事在java中的应用

Java中可重入锁-ReentrantLock基本上就是按照上面的思路来实现的,我们来对给他们做一个简单的对比。

一次只有一个人能打水 锁需要保证多线程的同步。

必须严格按照排队顺序打水 ReentrantLock提供的公平锁功能。

来得早不如来得巧 ReentrantLock提供的非公平锁功能。

有家人正在打水的时候就不需要排队 ReentrantLock的可重入特性。

那么可重入锁又是怎样实现上面那些特性的呢?

java可重入锁-ReentrantLock实现细节

首先我们从上面的故事入手,看看ReentrantLock中的各个角色都是怎么样的。

打水权 volatile int state

打水者 线程、Thread

打水队伍 双向链表Node

获取锁的时候,公平锁的整个工作流程就如下图所示:
java 可重入锁ReentrantLock的介绍

可重入公平锁获取流程

在获取锁的时候,如果当前线程之前已经获取到了锁,就会把state加1,在释放锁的时候会先减1,这样就保证了同一个锁可以被同一个线程获取多次,而不会出现死锁的情况。这就是ReentrantLock的可重入性。

对于非公平锁而言,调用lock方法后,会先尝试抢占锁,在各种判断的时候会先忽略等待队列,如果锁可用,就会直接抢占使用。

释放锁的时候,整个工作流程如下图:
java 可重入锁ReentrantLock的介绍

可重入锁释放过程

本文为转载:https://baijiahao.baidu.com/s?id=1594800969528243663&wfr=spider&for=pc
参考:https://blog.csdn.net/yanyan19880509/article/details/52345422