基于jdk1.8
看这篇文章之前,最好是先了解过AQS
可重入的独占锁
内部实现了公平和非公平两种同步器
可以获取Condition的具体实现
ReentrantLock+Condition可以实现唤醒特定的一组线程中的一个线程,对于同一个锁,它可以创建多个Condition,协调控制多组线程
ReentrantLock的UML
重要构造
内部有公平和非公平两种实现。
lock()
非公平实现 :NnfairSync
锁竞争激烈,可能会导致,某个线程长时间得不到执行,一直在等待。
/**
* 获取独占锁
*/
public void lock() {
sync.lock();
}
/**
* 尝试获取独占锁
*/
final void lock() {
//cas设置state的值
if (compareAndSetState(0, 1))
//cas设置成功 然后设置独占线程为当前线程
setExclusiveOwnerThread(Thread.currentThread());
else
//调用AQS中的模板方法 尝试获取独占锁
//最终会调用tryAcquire尝试获取独占锁
acquire(1);
}
/**
* 尝试获取独占锁
*/
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
tryAcquire中的nonfairTryAcquire是重点实现,如果这里尝试失败了,就会走AQS独占锁的流程,大概是加入阻塞队列,如果前驱是头节点就再次尝试获取,不然就尝试将线程挂起,具体的可以查看AQS的源码解析。
可以看到,在独占锁没有被获取的情况下,线程都会尝试获取独占锁,如果获取锁的线程再次获取锁是可以的,只是会增加线程的重入次数。
公平实现:FairSync
线程竞争激烈的,可能会没有长时间等待的情况,但每个线程都会经历挂起和唤醒的操作,消耗可能会大许多。
/**
* 获取独占锁
*/
public void lock() {
sync.lock();
}
/**
* 获取锁
*/
final void lock() {
//会调用tryAcquire尝试获取独占锁
acquire(1);
}
与非公平的区别就是在于hasQueuedPredecessors()这个方法,它会先判断阻塞队列中是否已经有节点了(是否已线程在等待获取锁),有的话,就不尝试获取了,直接排队,因为我们是公平的。
unlock()
非公平和公平两者的实现是一样的。
释放成功后的操作都是由AQS统一实现。
Condition的的具体实现在AQS源码解析二里面也已经详细讲解过了,这里也就不重复了。
ReentrantLock完整源码解析点击这里