一、概述
ReentrantLock是基于AQS实现的一种独占可重入锁,利用自旋和CAS实现的轻量锁,提供公平和非公平锁
二、常用方法
lock()
获取锁,如果不能获取则阻塞当前线程,直到获取锁
lockInterruptibly()
可中断的锁获取,与lock功能类似,如果线程中断则抛出InterruptedException
tryLock()
尝试获取锁,无论是否获取成功,立即返回
tryLock(long timeout, TimeUnit unit)
尝试获取锁,在超时时间内获取到锁则返回true,如果不能获取锁,则返回false;
unLock()
释放锁
三、源码
1、Sync同步器
提供了非公平锁的获取和
tryAcquire在各自子类实现
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -5179523762034025860L;
@ReservedStackAccess
final boolean nonfairTryAcquire(int acquires) {
// acquires代表需要获取锁的数量
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
// 非公平锁,可以直接竞争获取(state是AQS持有的一个计数器,表示锁获取的数量)
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
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;
}
// 释放锁
@ReservedStackAccess
protected final boolean tryRelease(int releases) {
// releases释放锁的数量
int c = getState() - releases;
// 未持有锁调用线程调用直接抛出IllegalMonitorStateException异常
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
// 锁全部释放则将独占线程设置为null
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
protected final boolean isHeldExclusively() {
// While we must in general read state before owner,
// we don't need to do so to check if current thread is owner
return getExclusiveOwnerThread() == Thread.currentThread();
}
final ConditionObject newCondition() {
return new ConditionObject();
}
// Methods relayed from outer class
final Thread getOwner() {
return getState() == 0 ? null : getExclusiveOwnerThread();
}
final int getHoldCount() {
return isHeldExclusively() ? getState() : 0;
}
final boolean isLocked() {
return getState() != 0;
}
/**
* Reconstitutes the instance from a stream (that is, deserializes it).
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
setState(0); // reset to unlocked state
}
}
2、非公平同步器
代码很简单,通过调用父类的nonfairTryAcquire方法尝试获取锁
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
3、公平同步器
除非是重入或者没有线程在队列等待,否则返回false
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
@ReservedStackAccess
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
// 没有线程持有锁,队列没有线程等待,CAS设置成功则获取锁
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
// 重入的场景,相当于单线程进入可直接修改state
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
}
4、构造函数
默认使用非公平锁
public ReentrantLock() {
sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
5、lock、lockInterruptibly
两者实现相似,lockInterruptibly如果线程中断则会抛出InterruptedException异常
public void lock() {
sync.acquire(1);
}
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
调用的是AQS中方法,下面可以看到AQS将会调用到子类实现的tryAcquire()来实现锁的获取
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
public final void acquireInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (!tryAcquire(arg))
doAcquireInterruptibly(arg);
}
6、tryLock
可以看到无论是公平还是非公平都是调用Sync提供非公平获取,这是一个需要立即返回结果的对锁的尝试获取
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
7、unlock
调用AQS中的释放
public void unlock() {
sync.release(1);
}
首先会调用子类实现的tryRelease,如果释放成功且有线程在等待则唤醒队列中等待线程
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}