ReentrantLock
Synchronized和ReentrantLock比较
Synchronized只支持非公平锁,ReentrantLock都支持
Synchronized不支持锁获取超时,ReentrantLock支持。
分为公平和非公平,公平情况下,走正常的尝试获取锁逻辑,先判断头节点后面是否有节点在等待。
非公平情况下,一上来就会尝试获取锁,获取失败,再走aqs一套逻辑,尝试获取锁的逻辑就不会判断头节点后面是否有节点在等待。
公平获取逻辑:
final void lock() {
acquire(1);
}
/**
* Fair version of tryAcquire. Don't grant access unless
* recursive call or no waiters or is first.
*/
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;
}
不公平获取锁逻辑
final void lock() {
//直接获取
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
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) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
ReentrantReadWriteLock 读写锁
高16位保存的是共享锁的个数,低16位保留的是独占锁的个数
获取读锁
Sync-》tryAcquireShared
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);
//readerShouldBlock方法有疑问。
if (!readerShouldBlock() &&
r < MAX_COUNT &&
compareAndSetState(c, c + SHARED_UNIT)) {
//共享锁加1.
if (r == 0) {
//第一个获取共享锁的线程
firstReader = current;
firstReaderHoldCount = 1;
} else if (firstReader == current) {
//当前为第一个获取共享锁的线程,第一个线程持有的共享锁个数加1。
firstReaderHoldCount++;
} else {
HoldCounter rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current))
//cachedHoldCounter 存储的是最后一个成功获取读锁的HoldCounter信息。
//cachedHoldCounter赋值。考虑的是不同线程第二次获取读锁后这种情况。
cachedHoldCounter = rh = readHolds.get();
else if (rh.count == 0)
//不同线程第三次获取到读锁后。
readHolds.set(rh);
rh.count++;
}
return 1;
}
return fullTryAcquireShared(current);
}
fullTryAcquireShared,主要是自旋获取共享锁。
final int fullTryAcquireShared(Thread current) {
/*
* This code is in part redundant with that in
* tryAcquireShared but is simpler overall by not
* complicating tryAcquireShared with interactions between
* retries and lazily reading hold counts.
*/
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)) {
//成功获取到共享锁,如下逻辑和tryAcquireShared中成功获取到成功锁的逻辑一模一样的
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;
}
}
}
ReentrantReadWriteLock释放读锁
Sync
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))
//nextc等于0,说明此时读和写锁都已经释放了,需要唤醒后续节点。
return nextc == 0;
}
}
ReentrantReadWriteLock获取写锁
protected final boolean tryAcquire(int acquires) {
Thread current = Thread.currentThread();
int c = getState();
int w = exclusiveCount(c);
if (c != 0) {
//如果c不等于0,而独占锁个数不为0,那么说明存在读锁还没释放。
if (w == 0 || current != getExclusiveOwnerThread())
return false;
if (w + exclusiveCount(acquires) > MAX_COUNT)
throw new Error("Maximum lock count exceeded");
// Reentrant acquire
//独占锁的个数在标志位的低16位,直接加acquires即可。
setState(c + acquires);
return true;
}
if (writerShouldBlock() ||
!compareAndSetState(c, c + acquires))
return false;
setExclusiveOwnerThread(current);
return true;
}
ReentrantReadWriteLock释放写锁
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;
}
主线逻辑:标志位减1-》设置独占线程为空。
ReentrantReadWriteLock公平与非公平区别
公平情况下
获取读锁,如果发现当前节点不是头节点后的节点,那么不能执行CAS获取共享锁。
获取写锁,如果发现当前节点不是头节点后的节点,那么不能执行CAS获取独占锁。
非公平情况下:
获取读锁:如果头节点后的节点为独占的,那么不能执行CAS获取共享锁
获取写锁:总是可以执行CAS获取独占锁。
ReentrantLock重写
@Slf4j
public class ReentrantLockRewrite extends AbstractQueuedSynchronizer {
@Override
protected boolean tryAcquire(int arg) {
int state = this.getState();
if (state == 0) {
if (compareAndSetState(0, arg)) {
log.info("获取锁成功");
setExclusiveOwnerThread(Thread.currentThread());
return true;
} else {
return false;
}
} else {
//可重入判断
if (Thread.currentThread() == getExclusiveOwnerThread()) {
log.info("线程重复获取锁");
setState(state + arg);
return true;
} else {
log.info("获取锁失败");
return false;
}
}
}
@Override
protected boolean tryRelease(int arg) {
if (Thread.currentThread() != getExclusiveOwnerThread()) {
throw new IllegalMonitorStateException("释放锁异常,释放线程不是当前获取锁的线程");
}
int state = getState();
int newState = state - arg;
if (state <= 0 || newState < 0) {
throw new IllegalArgumentException("释放锁异常");
}
setState(newState);
if (newState == 0) {
setExclusiveOwnerThread(null);
}
log.info("释放锁成功");
return true;
}
public void lock() {
this.acquire(1);
}
public void unlock() {
this.release(1);
}
}