ReentrantLock
实现Lock接口的一个类支持重入性,表示能够对共享资源能够重复加锁,及当前线程再次获取该锁不会被阻塞
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;
}
执行两种逻辑1.当前锁未被任何线程占有 则锁被当前线程获取 2.已经被线程占有判断是否是当前线程 ,如果是则获取锁对象计数+1
释放锁
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;
}
``
同步锁释放必须等到同步状态为0才能成功释放,当一个锁获取一次,计数+1,所以释放一次计数-1,若返回值同步状态不为0则为false
2.公平锁与非公平锁
一个公平锁获取顺序符合FIFO先到先得
ReentranLock无参构造时非公平锁
传入参数true公平锁false非公平锁
```javascript
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
公平锁每次都是从同步队列第一个节点获取锁,而非公平锁则不一定,所以公平锁保证请求资源的绝对顺序但是性能开销高于非公平锁。
ReentrantReadWriteLock
1.读写锁
独占锁一般synchhronized或者concurrents实现Lock接口ReentrantLock实现独占锁,同一时刻只有一个线程能够获取锁
读写所允许同一时刻被多个读线程访问,但是在写线程访问时,所有的读线程和其他的写线程都会被阻塞。
2.写锁的获取
同一时刻写锁不能被多个线程锁获取,写锁时独占式锁实现的方式重写AQS中的tryAcquire方法实现
protected final boolean tryAcquire(int acquires) {
Thread current = Thread.currentThread();
int c = getState(); // 1. 获取写锁当前的同步状态
int w = exclusiveCount(c); // 2. 获取写锁获取的次数
if (c != 0) {
// (Note: if c != 0 and w == 0 then shared count != 0)
// 3.1 当读锁已被读线程获取或者当前线程不是已经获取写锁的线程的话
// 当前线程获取写锁失败
if (w == 0 || current != getExclusiveOwnerThread())
return false;
if (w + exclusiveCount(acquires) > MAX_COUNT)
throw new Error("Maximum lock count exceeded");
// Reentrant acquire
// 3.2 当前线程获取写锁,支持可重复加锁
setState(c + acquires); //acquires重复加锁
return true;
}
// 3.3 写锁未被任何线程获取,当前线程可获取写锁
if (writerShouldBlock() ||
!compareAndSetState(c, c + acquires))
return false;
setExclusiveOwnerThread(current);
return true;
}
3.写锁的释放
重写AQS的tryRelease方法完成写锁的释放
protected final boolean tryRelease(int releases) {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
//1. 同步状态减去写状态
int nextc = getState() - releases;
//2. 当前写状态是否为0,为0则释放写锁
boolean free = exclusiveCount(nextc) == 0;
if (free)
setExclusiveOwnerThread(null);
//3. 不为0则更新同步状态
setState(nextc);
return free;
}
同步状态的情况下进入写锁类似于可重入锁的方式,将写锁也是为重入锁所以在释放时,用同步状态减去写状态带来的Monitor++;
4.读锁
读锁不是独占式锁,同一时刻多个线程可以同时获取的一种共享锁的方式
Thread current = Thread.currentThread();
int c = getState();
//1. 如果写锁已经被获取并且获取写锁的线程不是当前线程的话,当前
// 线程获取读锁失败返回-1
if (exclusiveCount(c) != 0 &&
getExclusiveOwnerThread() != current)
return -1;
int r = sharedCount(c);
if (!readerShouldBlock() &&
r < MAX_COUNT &&
//2. 当前线程获取读锁
compareAndSetState(c, c + SHARED_UNIT)) {
//3. 下面的代码主要是新增的一些功能,比如getReadHoldCount()方法
//返回当前获取读锁的次数
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;
}
//4. 处理在第二步中CAS操作失败的自旋已经实现重入性
return fullTryAcquireShared(current);
}
(1). 与写锁逻辑相同,对当前锁的状态进行胖多,如果写锁被获取,但是写锁线程不是当前线程,则失败不能进入写锁,CAS自旋成功进入,更新状态
(2). 当前线程成功获取读锁,返回读锁的次数
5.读锁的释放
protected final boolean tryReleaseShared(int unused) {
Thread current = Thread.currentThread();
if (firstReader == current) {
// assert firstReaderHoldCount > 0;
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))
// Releasing the read lock has no effect on readers,
// but it may allow waiting writers to proceed if
// both read and write locks are now free.
return nextc == 0;
}
}
6.锁降级
读写锁支持锁降级,遵循按照获取写锁,获取读锁再释放写锁的次序,写锁能够降级成为读锁。
[资源参考:https://www.jianshu.com/p/27860941a77b?tdsourcetag=s_pcqq_aiomsg 特此声明]