1. ReentrantLock的介绍
ReentrantLock重入锁,是实现Lock接口的一个类,也是在实际编程中使用频率很高的一个锁,支持重入性,表示能够对共享资源能够重复加锁,即当前线程获取该锁再次获取不会被阻塞。在java关键字synchronized隐式支持重入性(关于synchronized可以看这篇文章),synchronized通过获取自增,释放自减的方式实现重入。与此同时,ReentrantLock还支持公平锁和非公平锁两种方式。
那么,要想完完全全的弄懂ReentrantLock的话,主要也就是ReentrantLock同步语义的学习:1. 重入性的实现原理;2. 公平锁和非公平锁。
2. 重入性的实现原理
要想支持重入性,就要解决两个问题:
1. 在线程获取锁的时候,如果已经获取锁的线程是当前线程的话则直接再次获取成功;
2. 由于锁会被获取n次,那么只有锁在被释放同样的n次之后,该锁才算是完全释放成功。
通过这篇文章,我们知道,同步组件主要是通过重写AQS的几个protected方法来表达自己的同步语义。
针对第一个问题,我们来看看ReentrantLock是怎样实现的,以非公平锁为例,判断当前线程能否获得锁为例,核心方法为nonfairTryAcquire:
final boolean nonfairTryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();//1. 如果该锁未被任何线程占有,该锁能被当前线程获取if (c == 0) {if (compareAndSetState(0, acquires)) {setExclusiveOwnerThread(current);return true;}}//2.若被占有,检查占有线程是否是当前线程else if (current == getExclusiveOwnerThread()) {// 3. 再次获取,计数加一int nextc = c + acquires;if (nextc < 0) // overflowthrow new Error("Maximum lock count exceeded");setState(nextc);return true;}return false;}这段代码的逻辑也很简单,具体请看注释。
为了支持重入性,在第二步增加了处理逻辑,如果该锁已经被线程所占有了,会继续检查占有线程是否为当前线程,如果是的话,同步状态加1返回true,表示可以再次获取成功。
每次重新获取都会对同步状态进行加一的操作,那么释放的时候处理思路是怎样的了?(依然还是以非公平锁为例)核心方法为tryRelease:
protected final boolean tryRelease(int releases) {//1. 同步状态减1int c = getState() - releases;if (Thread.currentThread() != getExclusiveOwnerThread())throw new IllegalMonitorStateException();boolean free = false;if (c == 0) {//2. 只有当同步状态为0时,锁成功被释放,返回truefree = true;setExclusiveOwnerThread(null);}// 3. 锁未被完全释放,返回falsesetState(c);return free;}代码的逻辑请看注释,需要注意的是,重入锁的释放必须得等到同步状态为0时锁才算成功释放,否则锁仍未释放。如果锁被获取n次,释放了n-1次,该锁未完全释放返回false,只有被释放n次才算成功释放,返回true。
新闻热点
疑难解答
图片精选