前言
ReentrantLock是java.util.concurrent.locks包中的一个类,是独占锁,为最后一个执行lock操作成功且为释放锁的线程锁拥有.因为它是基于AQS实现的,先看下它和Synchronized的区别
- 便利性:Synchronized用法更简洁,由编译器去保证锁的加锁和释放; ReenTrantLock需要手动加锁和释放锁,为了避免忘记手工释放锁造成死锁,所以最好在finally中声明释放锁。
- 锁的细粒度和灵活度:ReenTrantLock优于Synchronized
此外,以下特点是ReenTrantLock独有:
1. ReenTrantLock可以指定是公平锁还是非公平锁; synchronized只能是非公平锁。
2. ReenTrantLock提供了一个Condition类,用来实现唤醒特定的线程; synchronized要么随机唤醒一个线程要么唤醒全部线程。
3. ReenTrantLock提供了一种能够中断等待锁的线程的机制。
接下来看下它的构成
Sync定义了abstract void lock();它的两个子类分别对其进行了实现,下面我们开始了解Sync
Sync.java
- nonfairTryAcquire(Sync中默认采用非公平方式尝试获取锁)
final
如果当前锁未被任何线程拥有(state==0),则通过compareAndSetState原子地设置state,然后把当前线程设置为自己,获取成功;
如果当前锁已经被线程占有,判断持有锁的线程是否为当前线程,若是,nextc+ acquires,获取成功;否则获取失败.
如果在它之前已经有很多线程等待锁,最后却被他获取,这里体现了非公平性.
- 尝试释放所 :tryRelease
protected
如果当前线程并非锁持有者,throw new IllegalMonitorStateException();如果是当前锁持有者,state减去release,判断state值,如果为0,说明完全释放,否则,还未完全释放.
接下来是一些简单的方法,就不解释了,直接看源码
protected
NonfairSync.java
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
/**
* Performs lock. Try immediate barge, backing up to normal
* acquire on failure.
*/
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
关于acquire方法,请参考深入学习java同步器
FairSync.java
static
在FairSync类的tryAcquire中会通过hasQueuedPredecessors()方法判断AQS的等待队列中是否前继节点,如果有,则不执行.这里体现了获取锁的公平性,等待越久的线程越先获取到锁
ReentrantLock.java
//默认使用非公平锁
AQS$hasQueuedThreads
public
AQS的等待队列中,是否有等待该条件的线程
我是伯仁,如果觉得文章对您有帮助,欢迎点赞关注.