锁系列文章:
java多线程系列7-AbstractQueuedSynchronizer源码分析
java多线程系列9-共享锁Semaphore源码解析
java多线程系列10-读写锁ReentrantReadWriteLock源码分析
1.ReentrantLock介绍
ReentrantLock是基于AQS实现的典型重入锁,在平时开发中或者其他源码类中出现频率也很高。在前一篇AQS源码分析基础上,分析下ReentrantLock的源码。ReentrantLock分为公平锁和非公平锁。
2.非公平锁
ReentrantLock默认是非公平锁,也可指定创建公平锁。
(1)默认非公平锁,也可构造公平锁
public ReentrantLock() {
sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
(2)加锁lock方法
final void lock() {
//设置state由0变成1,成功代表获取锁
if (compareAndSetState(0, 1))
//设置拥有锁的线程为当前线程
setExclusiveOwnerThread(Thread.currentThread());
else
//状态设值失败,尝试获取锁
acquire(1);
}
(3)acquire方法就是AQS中方法,在上一篇中已经说明,这里不再叙述,我们重点关注下子类实现的tryAcquire方法
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
(4)tryAcquire方法
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
(5)nonfairTryAcquire方法
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
//锁的状态
int c = getState();
if (c == 0) {
//状态为0,代表没有线程获取锁,城市获取锁
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
//状态为0,判断持有锁的线程是否为当前线程,如果是,将state加1,否则获取锁失败
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
3.公平锁
(1)lock方法
final void lock() {
acquire(1);
}
(2)acquire方法也是AQS方法
(3)tryAcquire
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
//如果state为0,首先判断队列中是否还有其他线程,没有才尝试设值state状态
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;
}
}
(4)hasQueuedPredecessors
public final boolean hasQueuedPredecessors() {
// The correctness of this depends on head being initialized
// before tail and on head.next being accurate if the current
// thread is first in queue.
Node t = tail; // Read fields in reverse initialization order
Node h = head;
Node s;
//如果tail和head不同,并且head的next为空或者head的next的线程不是当前线程,则表示队列不为空
//有两种情况会导致h的next为空:1。当前线程进入hasQueuedPredecessors的同时,另一个线程已经更改了tail(在enq中),但还没有将head的next指向自己,这中情况表明队列不为空;
// 2)当前线程将head赋予h后,head被另一个线程移出队列,导致h的next为空,这种情况说明锁已经被占用。
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());
}
3.释放锁
释放锁对公平和非公平都一样
(1)unlock方法
public void unlock() {
sync.release(1);
}
(2)release方法是AQS方法,上一篇已经详细分析过,这里重点关注tryRelease方法
(3)tryRelease
protected final boolean tryRelease(int releases) {
//判断锁可以重入,重入了几次,就需要退出线程,state为0,才代表当前线程已经完全退出,释放了锁
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
总结:
公平锁和非公平锁区部:
- 公平锁在判断没有线程获得锁下,或判断队列是否已经线程在等待,有的话并且获得锁线程不是自己就加入队列等待
- 非公平锁在获得锁时,就会尝试获得锁,没有成功,判断是否有线程已经获得锁,没有的话,再次尝试获得锁,没有成功并且获得锁线程不是自己,才会自己。