简介
在java中,实现锁有2种方式,一个是synchronized,一个是Lock,今天我们讲讲可重入锁ReentrantLock,ReentrantLock相对于传统的synchronized,优势在于提供了更加灵活的方式使用锁,比如可重入,锁超时,锁中断,公平、非公平锁。
ReentrantLock是基于AQS独占锁实现的, 阅读本文之前还需要了解几个概念:
- 可重入锁:指的是同一线程外层函数获得锁之后 ,内层递归函数仍然有获取该锁的代码。也就是同一线程可以获得多个锁。不然就会发生死锁问题。
- 可中断锁:在某些条件下可以相应中断的锁。在Java中,synchronized就不是可中断锁,而 Lock是可中断锁。
- 公平锁:公平锁即尽量以请求锁的顺序来获取锁。比如同是有多个线程在等待一个锁,当这个锁被释放时,等待时间最久的线程(最先请求的线程)会获得该所,这种就是公平锁。
- 非公平锁:无法保证锁的获取是按照请求锁的顺序进行的。有可能锁刚被释放,正好新来了个线程请求锁,这样后面等待的线程就不能获得锁。在极端情况下,可能导致一直无法获取锁。
源码分析
非公平锁
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
final void lock() {
if (compareAndSetState(0, 1))
//如果没有线程占用锁资源,直接独占资源,更新AQS类的state,当前线程独占
setExclusiveOwnerThread(Thread.currentThread());
else
//AQS类的acquire,调用实现类的tryAcquire
acquire(1);
}
/**
* 获取非公平锁
* 1. 当前无锁,给当前线程上锁
* 2. 当前有锁,但是加锁的线程是当前线程,增加状态值
* 其他情况返回false
*/
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
//非公平尝试获取锁
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
//如果资源没被任何线程占有过
if (compareAndSetState(0, acquires)) {
//cas成功,设置当前线程独占
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
//当前线程重入,state + 1
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
//添加到等待队列,等待通知
return false;
}
公平锁
公平锁和非公平锁的区别在于hasQueuedPredecessors(),它用来返回队列中是否有比当前线程等待更久的线程
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
final void lock() {
acquire(1);
}
/**
* 获取公平锁
* 1. 当前无锁,并且没有等待更久的线程的话,给当前线程上锁
* 2. 当前有锁,但是加锁的线程是当前线程,增加状态值
* 其他情况返回false
*/
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
}