重入锁
JUC中的重入锁ReentrantLock建立在AQS之上,其内部类Sync继承AQS,并实现其抽象方法,以完成可重入特性。实现可重入锁的需要注意的是:线程已经成功获取到锁才可重入;线程重入n次之后,历经释放n次,其他线程可以请求并获取到锁。在JUC重入锁的设计中提供了公平与非公平锁两种实现。其区别主要在于获取锁的顺序(公平锁有序),由于公平锁的有序性可能引起上下文切换,所以公平锁的吞吐性能表现不佳。
ReentranLock里面的功能均是委托给Sync实现,而Sync内部的lock()抽象方法由子类实现,下面给出非公平锁lock()方法的实现
final void lock() {
if (compareAndSetState(0, 1))//CAS设置状态
setExclusiveOwnerThread(Thread.currentThread());
else//获取锁失败
acquire(1);
}
在该lock()方法中,首先快速CAS设置状态值(0时无锁状态),获取失败则调用AQS的acquire(int arg)方法,非公平锁的抽象方法tryAcquire(int arg),实际是对Sync中nonfairTryAcquire(int acquires)的包装
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {//无锁状态
if (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;
}
公平锁的获取则是直接调用AQS中的模板方法acquire(int arg);
final void lock() {
acquire(1);
}
公平锁抽象方法的实现
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;
}
}
对比公平锁与非公平锁的tryAcquire抽象方法的实现,公平锁在获取锁时必须为同步队列中的第一个节点,其他细节实现基本一致
在ReentranLock锁的释放中,委托给Sync的relase(int arg)执行,同时Sync内部实现了AQS的抽象方法tryRelease(int arg)
protected final boolean tryRelease(int releases) {
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;
}
读写锁
读写锁ReentrantReadWriteLock,将锁包装为读锁与写锁,允许多个读锁线程同时访问,但是在写线程时,其他线程的写与读均被阻塞。通过分离读锁与写锁,使得锁的性能大大提升。其特性如下:
读写锁内部与重入锁类似包含内部类Sync继承至AQS并实现相应的抽象方法。在该Sync中volatile的状态变量维护需要维护读和写两种锁的状态,状态变量采用低16位维护写锁状态,高16位维护读锁状态。因此写状态为 (S&0x0000FFFF),读状态为(S>>16)。
1、关于公平性
在读写锁的设计中Sync定义了抽象方法
1) final boolean writerShouldBlock();
2) final boolean readerShouldBlock();
NonfairSync与FairSync继承Sync并实现上述抽象方法以实现公平与非公平获取功能
2、读与写锁
读锁ReadLock(共享锁)的lock()获取委托sync.acquireShared(1)实现,unlock()释放委托给sync.releaseShared(1)实现
写锁WriteLock(互斥锁)的lock()委托sync.acquire(1)实现,unlock()释放委托给sync.release(1)实现
此外读锁与写锁的超时,中断响应等也是委托给sync实现
最后来看看,Sync中关于AQS抽象方法的具体实现。
写锁获取依赖的抽象方法tryAcquire(int acquires)
protected final boolean tryAcquire(int acquires) {
Thread current = Thread.currentThread();
int c = getState();
int w = exclusiveCount(c);//写锁状态
if (c != 0) {//有线程获取到锁
//存在读锁且获取读锁的线程不为当前线程,写锁获取失败
if (w == 0 || current != getExclusiveOwnerThread())
return false;
if (w + exclusiveCount(acquires) > MAX_COUNT)
throw new Error("Maximum lock count exceeded");
setState(c + acquires);
return true;
}
if (writerShouldBlock() ||
!compareAndSetState(c, c + acquires))
return false;
setExclusiveOwnerThread(current);//设置线程独占
return true;
}
写锁释放依赖的抽象方法tryRelease(int acquires)
protected final boolean tryRelease(int releases) {
if (!isHeldExclusively())//非独占,异常
throw new IllegalMonitorStateException();
int nextc = getState() - releases;
boolean free = exclusiveCount(nextc) == 0;//重入写锁完成释放
if (free)
setExclusiveOwnerThread(null);
setState(nextc);
return free;
}
读锁的获取依赖抽象方法tryAcquireShared(int acquires)
protected final int tryAcquireShared(int unused) {
Thread current = Thread.currentThread();
int c = getState();
if (exclusiveCount(c) != 0 &&
getExclusiveOwnerThread() != current)//其他线程获取到写锁
return -1;
int r = sharedCount(c);
/*读锁是否需要等待(公共性) ** 读锁可重入限制 */
if (!readerShouldBlock() &&
r < MAX_COUNT &&
compareAndSetState(c, c + SHARED_UNIT)) {
if (r == 0) {
firstReader = current;
firstReaderHoldCount = 1;
} else if (firstReader == current) {//首次获取
firstReaderHoldCount++;
} else {//缓存当前线程读锁计数
HoldCounter rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current))
cachedHoldCounter = rh = readHolds.get();
else if (rh.count == 0)
readHolds.set(rh);
rh.count++;//更新读锁计数
}
return 1;
}
return fullTryAcquireShared(current);
}
当获取读锁不满足公平性条件或持有线程数不满足时,执行fullTryAcquireShared(current)
final int fullTryAcquireShared(Thread current) {
HoldCounter rh = null;
for (;;) {
int c = getState();
if (exclusiveCount(c) != 0) {//存在写锁
if (getExclusiveOwnerThread() != current)//写锁不为当前线程
return -1;
} else if (readerShouldBlock()) {//读锁需要阻塞
if (firstReader == current) {
// assert firstReaderHoldCount > 0;
} else {
if (rh == null) {
rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current)) {
rh = readHolds.get();
if (rh.count == 0)
readHolds.remove();
}
}
if (rh.count == 0)
return -1;
}
}
//超出最大范围
if (sharedCount(c) == MAX_COUNT)
throw new Error("Maximum lock count exceeded");
if (compareAndSetState(c, c + SHARED_UNIT)) {
if (sharedCount(c) == 0) {//锁被首次获取
firstReader = current;
firstReaderHoldCount = 1;
} else if (firstReader == current) {//当前线程为第一个获取锁的线程
firstReaderHoldCount++;
} else {
if (rh == null)
rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current))
rh = readHolds.get();
else if (rh.count == 0)
readHolds.set(rh);
rh.count++;//更新读锁计数
cachedHoldCounter = rh; // cache for release
}
return 1;
}
}
}
读锁的释放依赖的抽象方法tryReleaseShared(int acquires)
protected final boolean tryReleaseShared(int unused) {
Thread current = Thread.currentThread();
if (firstReader == current) {//当前线程为第一个读锁获取线程
if (firstReaderHoldCount == 1)//只获取过一次
firstReader = null;
else//该线程重入多次
firstReaderHoldCount--;
} else {/缓存当前线程读锁计数
HoldCounter rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current))
rh = readHolds.get();
int count = rh.count;//当前线程读锁计数值
if (count <= 1) {
readHolds.remove();//移除线程缓存
if (count <= 0)
throw unmatchedUnlockException();
}
--rh.count;//更新线程读锁计数值
}
for (;;) {
int c = getState();
int nextc = c - SHARED_UNIT;
if (compareAndSetState(c, nextc))//CAS设置锁状态值
return nextc == 0;
}
}